home *** CD-ROM | disk | FTP | other *** search
/ Joytech 2005 (USA) / Joytech 2005 (USA).bin / mac / installers / Adobe Reader 6.0 / Adobe Reader 6.0.app / Contents / MacOS / Updater / bootstrap.js < prev   
Text File  |  2003-10-29  |  101KB  |  2,938 lines

  1. //
  2. // All scripts (master, data, code, ui, maintainance, etc) should obey the
  3. // following conventions:
  4. //
  5. // -- each script can define one and only one object.  eval() returns the
  6. // result of evaluating the last statement of the script.  therefore, the
  7. // last statement of all script should simply be the script obj.
  8. // 
  9. // -- has a "version" key
  10. // 
  11. // --  more to be added
  12.  
  13. // constants used during evaluation for dialog descriptions
  14. var isMac = new Boolean(updater.app.platform.substr(0,3) == "MAC");
  15. var isWin = new Boolean(updater.app.platform.substr(0,3) == "WIN");
  16. var isReader = new Boolean((updater.app.viewerType.substr(0,6) == "Reader"));
  17.  
  18. var nextCheckText = (updater.app.getUpdaterString("IDS_PREFS_PANEL_NEXTCHECK"));
  19. var manualNextCheck = (updater.app.getUpdaterString("IDS_PREFS_PANEL_MANUALNEXTCHECK"));
  20. var checkForUpdatesText = (updater.app.getUpdaterString("IDS_PREFS_PANEL_CHECKTXT"));
  21. var updateAcrobatNowText = (updater.app.getUpdaterString("IDS_UPDATE_ACROBAT_NOW"));
  22. var updateReaderNowText = (updater.app.getUpdaterString("IDS_UPDATE_READER_NOW"));
  23. var updateNotificationBtn = (updater.app.getUpdaterString("IDS_PREFS_PANEL_VIEW_NOTIFS"));
  24. var showConfirmDlgText = (updater.app.getUpdaterString("IDS_UPDATE_AUTO_CONF_TXT"));
  25. var displayStartupNotifDlgText = (updater.app.getUpdaterString("IDS_UPDATE_SHOW_NOTIF_TXT"));
  26.  
  27. // calcuate width of the button 
  28. var gStaticTextWidth = 8;
  29. //var gUpdateNowWidth =  (gStaticTextWidth * Math.max(updateAcrobatNowText.length, updateReaderNowText.length));
  30. var gUpdateNowWidth = (gStaticTextWidth * updateNotificationBtn.length);
  31.  
  32. var ScriptObj = {
  33.  
  34.     version:"0.30",
  35.  
  36.     // Localized JS strings needed by the Pref Panel -- copy these directly from ResourceScript.js files.
  37.     PrefPanelLocJSStrings:
  38.     {
  39.         "ENU" :
  40.         {
  41.             "UIS_INUPS_INSTALLED_UPDATES" : "Installed Updates"
  42.         },
  43.         "CHS" :
  44.         {
  45.             "UIS_INUPS_INSTALLED_UPDATES" : "\u5DF2\u5B89\u88C5\u7684\u66F4\u65B0"
  46.         },
  47.         "CHT" :
  48.         {
  49.             "UIS_INUPS_INSTALLED_UPDATES" : "\u5DF2\u5B89\u88DD\u7684\u66F4\u65B0\u5167\u5BB9"
  50.         },
  51.         "DAN" :
  52.         {
  53.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0049\u006E\u0073\u0074\u0061\u006C\u006C\u0065\u0072\u0065\u0064\u0065\u0020\u006F\u0070\u0064\u0061\u0074\u0065\u0072\u0069\u006E\u0067\u0065\u0072"
  54.         },
  55.         "DEU" :
  56.         {
  57.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0049\u006E\u0073\u0074\u0061\u006C\u006C\u0069\u0065\u0072\u0074\u0065\u0020\u0055\u0070\u0064\u0061\u0074\u0065\u0073"
  58.         },
  59.         "ESP" :
  60.         {
  61.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0041\u0063\u0074\u0075\u0061\u006C\u0069\u007A\u0061\u0063\u0069\u006F\u006E\u0065\u0073\u0020\u0069\u006E\u0073\u0074\u0061\u006C\u0061\u0064\u0061\u0073"
  62.         },
  63.         "FRA" :
  64.         {
  65.             "UIS_INUPS_INSTALLED_UPDATES" : "\u004D\u0069\u0073\u0065\u0073\u0020\u00E0\u0020\u006A\u006F\u0075\u0072\u0020\u0069\u006E\u0073\u0074\u0061\u006C\u006C\u00E9\u0065\u0073"
  66.         },
  67.         "ITA" :
  68.         {
  69.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0041\u0067\u0067\u0069\u006F\u0072\u006E\u0061\u006D\u0065\u006E\u0074\u0069\u0020\u0069\u006E\u0073\u0074\u0061\u006C\u006C\u0061\u0074\u0069"
  70.         },
  71.         "JPN" :
  72.         {
  73.             "UIS_INUPS_INSTALLED_UPDATES" : "\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u305F\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8"
  74.         },
  75.         "KOR" :
  76.         {
  77.             "UIS_INUPS_INSTALLED_UPDATES" : "\uC124\uCE58\uB41C\u0020\uC5C5\uB370\uC774\uD2B8"
  78.         },
  79.         "NLD" :
  80.         {
  81.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0047\u0065\u00EF\u006E\u0073\u0074\u0061\u006C\u006C\u0065\u0065\u0072\u0064\u0065\u0020\u0075\u0070\u0064\u0061\u0074\u0065\u0073"
  82.         },
  83.         "NOR" :
  84.         {
  85.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0049\u006E\u0073\u0074\u0061\u006C\u006C\u0065\u0072\u0074\u0065\u0020\u006F\u0070\u0070\u0064\u0061\u0074\u0065\u0072\u0069\u006E\u0067\u0065\u0072"
  86.         },
  87.         "PTB" :
  88.         {
  89.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0041\u0074\u0075\u0061\u006C\u0069\u007A\u0061\u00E7\u00F5\u0065\u0073\u0020\u0069\u006E\u0073\u0074\u0061\u006C\u0061\u0064\u0061\u0073"
  90.         },
  91.         "SUO" :
  92.         {
  93.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0041\u0073\u0065\u006E\u006E\u0065\u0074\u0075\u0074\u0020\u0070\u00E4\u0069\u0076\u0069\u0074\u0079\u006B\u0073\u0065\u0074"
  94.         },
  95.         "SVE" :
  96.         {
  97.             "UIS_INUPS_INSTALLED_UPDATES" : "\u0049\u006E\u0073\u0074\u0061\u006C\u006C\u0065\u0072\u0061\u0064\u0065\u0020\u0075\u0070\u0070\u0064\u0061\u0074\u0065\u0072\u0069\u006E\u0067\u0061\u0072"
  98.         }
  99.     },
  100.  
  101.     getPrefPanelLocStr: function(strID)
  102.     {
  103.         updater.MasterScript.assert(strID && (strID.length > 0), "invalid string id");
  104.  
  105.         var appLang = updater.MasterScript.getAppLang();
  106.         if (updater.MasterScript.PropertyIsDefined(updater.MasterScript.PrefPanelLocJSStrings, appLang))
  107.         {
  108.             var strRes = updater.MasterScript.PrefPanelLocJSStrings[appLang];
  109.  
  110.             if (updater.MasterScript.PropertyIsDefined(strRes, strID))
  111.             {
  112.                 return strRes[strID];
  113.             }
  114.             else
  115.             {
  116.                 // Try ENU if strID is missing from nonENU string resource.
  117.                 strRes = updater.MasterScript.PrefPanelLocJSStrings["ENU"];
  118.                 if (updater.MasterScript.PropertyIsDefined(strRes, strID))
  119.                 {
  120.                     return strRes[strID];
  121.                 }
  122.                 else
  123.                 {
  124.                     return "MISSING_STRID_" + strID;
  125.                 }
  126.             }
  127.         }
  128.         else
  129.         {
  130.             return "MISSING_STRING_RESOURCE_" + appLang;
  131.         }
  132.     },
  133.  
  134.     prodConfigToURLMap: {
  135.       "Exchange-Pro": "pro",
  136.       "Exchange" : "std",
  137.       "Reader" : "rdr"
  138.     },
  139.  
  140.     scriptRootTemplate: "_PRODCONF_/_PLATFORM_/_LANG_/",
  141.  
  142.     getScriptRootURL: function()
  143.     {
  144.       var prod, platform, lang;
  145.       
  146.       prod = this.prodConfigToURLMap[updater.app.viewerType];
  147.       this.assert(prod.length > 0, "Invalid Product Config");
  148.       
  149.       platform = updater.app.platform.toLowerCase();
  150.  
  151.       var lang;
  152.  
  153.       var tier = this.getAppTier();
  154.  
  155.       // user is in cross tier config
  156.       if (tier.toLowerCase() == "all") { lang = "all"; }
  157.       else if (tier.toLowerCase() == "enu") { lang = "enu"; }
  158.       // else { lang = this.getDefLangForTier(tier).toLowerCase(); }
  159.       // always use running lang to produce the URL
  160.       else { lang = this.getAppLang().toLowerCase(); }
  161.  
  162.       // Fix for bug #644289 -- blocker on JPN Mac.
  163.       if (updater.app.platform.substr(0,3) == "MAC")
  164.       {
  165.           lang += "_601";
  166.       }
  167.  
  168.       var urlext = new String(this.scriptRootTemplate);
  169.  
  170.       urlext = urlext.replace(/_PRODCONF_/, prod);
  171.       urlext = urlext.replace(/_PLATFORM_/, platform);
  172.       urlext = urlext.replace(/_LANG_/, lang);
  173.       
  174.       updater.console.println("url ext = " + urlext);
  175.       
  176.       return updater.scriptRootURL + urlext;
  177.     },
  178.     
  179.     getDSURL: function()
  180.     {
  181.         var dsfile = "DataScript.js";
  182.         var ret = this.getScriptRootURL() + dsfile;
  183.         return ret;
  184.     },
  185.  
  186.  
  187.     //
  188.     // The App Tier and Language  API
  189.     //
  190.     // The Language code
  191.     //
  192.     //      {"DEU", "de-DE"},
  193.     //         {"ESP", "es-ES"},
  194.     //         {"FRA", "fr-FR"},
  195.     //         {"ITA", "it-IT"},
  196.     //         {"JPN", "ja-JP"},
  197.     //         {"NLD", "nl-NL"},
  198.     //         {"SVE", "sv-SE"},
  199.     //         {"SUO", "fi-FI"},
  200.     //         {"NOR", "no-NO"},
  201.     //         {"NON", "no-NO"},
  202.     //         {"DAN", "da-DK"},
  203.     //         {"KOR", "ko-KR"},
  204.     //         {"PTB", "pt-BR"},
  205.     //         {"CHS", "zh-CN"},
  206.     //         {"CHT", "zh-TW"},
  207.     //         {"ENU", "en-US"}
  208.     //
  209.   
  210.     // language code id to description
  211.     LangToDescMap:
  212.     {
  213.     "ENU" : "English",
  214.     "JPN" : "Japanese",
  215.     "CHT" : "Chinese Traditional",
  216.     "CHS" : "Chinese Simplified",
  217.     "KOR" : "Korean",
  218.     "FRA" : "French",
  219.     "DEU" : "German",
  220.     "PTB" : "Portuguese Brazil",
  221.     "ITA" : "Italian",
  222.     "NLD" : "Dutch",
  223.     "ESP" : "Spanish",
  224.     "SVE" : "Swedish",
  225.     "DAN" : "Danish",
  226.     "SUO" : "Finish",
  227.     "NOR" : "Norwegian",
  228.     "HEB" : "Hebrew",
  229.     "ARA" : "Arabic"
  230.     },
  231.  
  232.     // Map either ISO4Char or RFC1766 to language code id
  233.     CountryToLangMap: 
  234.     {
  235.     "en"    : "ENU",
  236.     "en-us" : "ENU",
  237.     "ja"    : "JPN",
  238.     "ja-jp" : "JPN",
  239.     "zh-tw" : "CHT",
  240.     "zh-cn" : "CHS",
  241.     "ko"    : "KOR", 
  242.     "ko-kr" : "KOR",
  243.     "fr"    : "FRA",
  244.     "fr-fr" : "FRA",
  245.     "de"    : "DEU",
  246.     "de-de" : "DEU",
  247.     "pt"    : "PTB",
  248.     "pt-br" : "PTB",
  249.     "it"    : "ITA",
  250.     "it-it" : "ITA",
  251.     "nl"    : "NLD",
  252.     "nl-nl" : "NLD",
  253.     "es"    : "ESP",
  254.     "es-sp" : "ESP",
  255.     "sv"    : "SVE",
  256.     "sv-se" : "SVE",
  257.     "da"    : "DAN",
  258.     "da-dk" : "DAN",
  259.     "fi"    : "SUO",
  260.     "fi-fi" : "SUO",
  261.     "no"    : "NOR",
  262.     "no-no" : "NOR",
  263.     "he"    : "HEB",
  264.     "he-il" : "HEB",
  265.     "ar"    : "ARA",
  266.     "ar-ae" : "ARA"
  267.     },
  268.  
  269.     // TODO: need to update the tier map
  270.     // Map Tier to lang in lang code id
  271.     TierToLangsMap:
  272.     {
  273.     "EFGJ" : ["FRA", "DEU", "JPN"],
  274.     "CCK"  : ["CHT", "CHS", "KOR"],
  275.     "DDS"  : ["DAN", "NLD", "SVE"],
  276.     "NF"   : ["NOR", "SUO"],
  277.     "SIP"  : ["ESP", "ITA", "PTB"]
  278.     },
  279.  
  280.     // if the app is in a tier BUT running in ENU, which is always available,
  281.     // then we need to have a default lang for the tier so that we know where
  282.     // to fetch the correct DataScript from
  283.     getDefLangForTier: function(tier) {
  284.       var m = this.TierToLangsMap;
  285.       for (var i in this.TierToLangsMap) {
  286.         if (i.toLowerCase() == tier.toLowerCase()) {
  287.           return m[i][0]; // the first element in array is the default lang
  288.           }
  289.         }
  290.       updater.MasterScript.assert(false, "Invalid Tier: " + tier);
  291.       return "ENU";  // just in case something really bad happens
  292.     },
  293.  
  294.     getAppLang: function() {
  295.       if ( ! updater.MasterScript.PropertyIsDefined(updater, "appLang") ||
  296.            updater.appLang == null ) 
  297.         {
  298.         updater.appLang = updater.app.language;
  299.         }
  300.       return updater.appLang;
  301.     },
  302.   
  303.     // Returns
  304.     // 1. ENU iff ENU is the only lang the app has
  305.     // 2. ALL if app has cross tier lang res
  306.     // 3. one of the key in TierToLangsMap reflecting the tier app is in
  307.     getAppTier: function() {
  308.  
  309.       if ( updater.MasterScript.PropertyIsDefined(updater, "appTier") &&
  310.            updater.appTier != null ) {
  311.         return updater.appTier;
  312.         }
  313.  
  314.       updater.console.println("app is running with lang = " + this.getAppLang());
  315.     
  316.       // determine tier
  317.       var res;
  318.       try {
  319.         res = this.getLangRes();
  320.         }
  321.       catch (e) {
  322.         updater.console.println("Exception calling getLangRes()" + e);
  323.         this.assert(false, "  getLangRes() exception");
  324.         updater.console.println("  defaulting res to ENU");
  325.         res = new Array();
  326.         res[0] = "ENU";
  327.         }
  328.     
  329.       updater.console.println("app has follow lang resources = " + res);
  330.  
  331.       if (res.length == 1) { 
  332.         // if the app has ONLY single lang has, it MUST be ENU
  333.         updater.MasterScript.assert(res[0] == "ENU", "Single Lang res MUST be ENU");
  334.         updater.appTier = res[0];
  335.         return res[0]; 
  336.         }
  337.     
  338.       var dup = {};  // used as a boolean bitmap
  339.       var t = Array();  // list of tiers
  340.       
  341.       // narrow down to Tiers given all the res available
  342.       for ( var i in res ) {
  343.         // skip ENU cause all config has ENU
  344.         if (res[i] == "ENU") { continue; }
  345.  
  346.         var tier = this.mapLangToTier(res[i]);
  347.         if ( ! updater.MasterScript.PropertyIsDefined(dup, tier) ) {
  348.           dup[tier] = true;
  349.           t.push(tier);
  350.           }
  351.         // updater.MasterScript.DumpObject(dup, "dup", true);
  352.         }
  353.       
  354.       updater.console.println("app is in tier = " + t);
  355.       
  356.       if (t.length == 1) {
  357.         updater.appTier = t[0];
  358.         }
  359.       else {
  360.         updater.console.println("app is in Multi-Tier = " + t);
  361.         updater.appTier = "ALL";
  362.         }
  363.       return updater.appTier;
  364.     },
  365.     
  366.     mapLangToTier: function(lang) {
  367.       var m = this.TierToLangsMap;
  368.       for ( var tier in m ) {
  369.         var langs = m[tier];
  370.         for ( var i in langs) {
  371.           if ( lang.toLowerCase() == langs[i].toLowerCase() ) return tier;
  372.           }
  373.         }
  374.       updater.MasterScript.assert(false, "Input Lang invalid: " + lang);
  375.     },
  376.  
  377.   
  378.     // return array of resources in Country Code app has.
  379.     // ENU MUST always be in the array.
  380.     getLangRes: function() {
  381.       var langRet = new Array();
  382.  
  383.       if (updater.app.platform == "WIN") {
  384.         var type = updater.app.viewerType;
  385.         var winLangFileBase;
  386.         if ( type == "Reader" ) {
  387.            winLangFileBase = "RdLang32";
  388.           }
  389.         else {
  390.           winLangFileBase = "ExLang32";
  391.           }
  392.         var avSpCat = updater.fileSys.AVSpecialCategory;
  393.         var avSpFold = updater.fileSys.AVSpecialFolder;
  394.       
  395.         var resRoot = updater.fileSys.GetSpecialFolder(avSpCat["kAVSCApp"], 
  396.                                                        avSpFold["kAVSFRoot"]);
  397.         updater.console.println("Enum items in mdPath: " + resRoot.mdPath);
  398.         var files = updater.fileSys.enumFolderItems(resRoot.mdPath);
  399.         var idx = 0;
  400.  
  401.         // win always have ENU
  402.         langRet[idx++] = "ENU";
  403.       
  404.         for (var i = 0; i < files.length; i++) {
  405.           //updater.console.println(" file = " + files[i].fileNameBase + "   ext = " + files[i].fileNameExt);
  406.         
  407.           if( files[i].isExistingFile  &&
  408.               (this.getFileNameBase(files[i].fileName).toLowerCase() 
  409.                == winLangFileBase.toLowerCase() ) )
  410.             {
  411.             var lcode = this.getFileNameExt(files[i].fileName).toLowerCase();
  412.             updater.console.println(" lcode = " + lcode);
  413.             if ( typeof(lcode) != "undefined" ) { langRet[idx++] = lcode; }
  414.             }
  415.           }
  416.         }
  417.       else if (updater.app.platform == "MAC") {
  418.         var macLangFileExt = "lproj";
  419.       
  420.         var avSpCat = updater.fileSys.AVSpecialCategory;
  421.         var avSpFold = updater.fileSys.AVSpecialFolder;
  422.       
  423.         var resRoot = updater.fileSys.GetSpecialFolder(avSpCat["kAVSCApp"], 
  424.                                                        avSpFold["kAVSFRoot"]);
  425.         // no special folder defined to access lang resource folder.
  426.         // manually create the path from app root:
  427.         //    /Acrobat 6.0.app/Contents/MacOS/
  428.         // -->/Acrobat 6.0.app/Contents/Resources/
  429.         var dip = new String(resRoot.diPath);
  430.         var resPath = dip.replace(/MacOS/, "Resources");
  431.         updater.console.println("Enum items in diPath: " + resPath);
  432.         var files = updater.fileSys.enumFolderItems(resPath, true);
  433.         var idx = 0;
  434.       
  435.         for (var i = 0; i < files.length; i++) {
  436.           //updater.console.println(" file = " + files[i].fileNameBase + "   ext = " + files[i].fileNameExt);
  437.         
  438.           if( files[i].isExistingFolder  &&
  439.               (this.getFileNameExt(files[i].fileName).toLowerCase() 
  440.                == macLangFileExt.toLowerCase() ) )
  441.             {
  442.             var cnt = this.getFileNameBase(files[i].fileName).toLowerCase();
  443.             // Mac may use underscore instead of dash in country lang code 
  444.             // ie: "zh_cn" instead of "zh-cn".  
  445.             // replace it with dash.
  446.             cnt = cnt.replace(/_/, "-");
  447.             var lcode = this.CountryToLangMap[cnt];
  448.             updater.console.println(" cnt   = " + cnt);
  449.             updater.console.println(" lcode = " + lcode);
  450.             this.assert(lcode.length > 0, "Cannot find " + cnt + " in CountryToLangMap");
  451.             if ( typeof(lcode) != "undefined" ) { langRet[idx++] = lcode; }
  452.             }
  453.           }
  454.         }
  455.       else {
  456.         this.assert(false, "Unsupported platform : " + updater.app.platform);
  457.         return null;
  458.         }
  459.     
  460.       return langRet;
  461.     },
  462.  
  463.     // base.ext
  464.     getFileNameBase: function(fn) {
  465.       var sep = fn.indexOf(".");
  466.       if (sep == -1) return fn;
  467.       return fn.substring(0, sep);
  468.     },
  469.  
  470.     // base.ext
  471.     getFileNameExt: function(fn) {
  472.       var sep = fn.indexOf(".");
  473.       if (sep == -1) return "";
  474.       return fn.substring(sep + 1, fn.length);
  475.     },
  476.  
  477.  
  478.     // pop a dialog and return true if restart pending.
  479.     checkPendingRestart: function(silent) 
  480.     {
  481.       var restartPending;
  482.       
  483.       if ( typeof(updater["restartPending"]) != "undefined") {
  484.         updater.console.println("===> App Restart Pending!  Skip Running Updater");
  485.         restartPending = updater.restartPending;
  486.         
  487.         // need restarting Acrobat...  
  488.         if (! silent) {
  489.           var title = updater.app.getUpdaterString("uisJSNeedRestartTitle");
  490.           var type = updater.app.viewerType;
  491.           var infoMsg;
  492.           if ( type == "Reader" ) {
  493.             infoMsg = updater.app.getUpdaterString("uisJSNeedRestartTxtRdr");
  494.             }
  495.           else {
  496.             infoMsg = updater.app.getUpdaterString("uisJSNeedRestartTxtVwr");
  497.             }
  498.           updater.app.alert({nIcon:3, nType:0, cTitle:title, cMsg:infoMsg});  
  499.           }
  500.         }
  501.       else {
  502.         restartPending = false;
  503.         }
  504.       return restartPending;
  505.     },
  506.  
  507.     // ALL MasterScript entry point MUST call init() before proceeding.
  508.     // if init() returns false, caller should exit and not proceed.
  509.     init: function(silent)
  510.     {
  511.       updater.console.println("MasterScript init() - silent = " + silent);
  512.       
  513.       if (updater.app.getUpdateDisabled()) {
  514.         updater.console.println("   Updater Disabled!!");
  515.         return false;
  516.       }
  517.       
  518.       // checkPendingRestart is the only init func for now.
  519.       // may have more MasterScript global init func later.
  520.       var ret = this.checkPendingRestart(silent);
  521.  
  522.       // don't cont if restart pending
  523.       var toCont = !ret;
  524.  
  525.       updater.console.println("MasterScript init() - to continue = " + toCont);
  526.       return (toCont);
  527.     },
  528.  
  529.     //
  530.     // Main Entry point for doing manual or auto updates
  531.     //
  532.     // set force to true for manual update, otherwise, it determines if it is
  533.     // time to update for the auto update case
  534.     // 
  535.     entryPoint: function(force)
  536.     {
  537.       force ? this.ManualUpdateAsync() : this.AutoUpdateAsync();
  538.     },
  539.  
  540.     // 
  541.     // utils function 
  542.     //
  543.     PropertyIsDefined: function( obj, propName )
  544.     {
  545.         var ret = (typeof( obj[ propName ] ) != "undefined");
  546.         // updater.console.println("PropertyIsDefined returns " + ret + " for " + propName);
  547.         return ret;
  548.     },
  549.  
  550.     DumpStrObj: function (obj) {
  551.       // updater.console.println("  ---- DumpStrObj -----");
  552.       updater.console.println("  obj.length = " + obj.length);
  553.       for (var i = 0; i < obj.length; i++) {
  554.         updater.console.println("  charcode obj[" + i + "] = " + obj.charCodeAt(i));
  555.       }
  556.       // updater.console.println("  ---- DumpStrObj End -----");
  557.     },
  558.     
  559.     // improve it to dump recursively later if i have time
  560.     DumpObject: function (obj, str, vals) {
  561.       if (! str ) str = "";
  562.       else str = str + " ";
  563.       str += "(" + obj + ") [" + typeof(obj) + "]\n";
  564.       for (var p in obj) {
  565.         str += "  " + p + ( vals ? ": " + obj[p] : "") + "\n";
  566.       }
  567.       updater.console.println(str);
  568.     },
  569.  
  570.     DumpArray: function (array, str) {
  571.       if (! str ) str = "";
  572.       else str = str + " ";
  573.       str += "(" + array + ") [" + typeof(array) + "]\n{ ";
  574.       for( var i = 0;  i < array.length;  i++ ) {
  575.         str += array[i] + ( i < array.length - 1 ? ", " : " }" );
  576.       }
  577.       updater.console.println(str);
  578.     },
  579.  
  580.     GetFunctionName: function(f) {
  581.       var name = f.toString().match(/(function .*\))/)[1];
  582.  
  583.       if ((name == null) || (name.length == 0))
  584.         name = 'anonymous';
  585.  
  586.       return name;
  587.     },
  588.  
  589.     StackTrace: function() 
  590.     {
  591.       var ret = '';
  592.       for (var i = arguments.callee.caller; i != null; i = i.caller) {
  593.         if (i) {
  594.           ret += '> ' + this.GetFunctionName(i) + '\n';
  595.         }
  596.         // if (i.caller == i) {
  597.         //           ret += '*';
  598.         //           break;
  599.         //         }
  600.       }
  601.       return ret;
  602.     },
  603.  
  604.     assert: function(cond, details) {
  605.       if (!cond) {
  606.         var msg = "!!!!! Assert failure ";
  607.         if (details) {
  608.           msg = msg + " - " + details;
  609.         }
  610.         if (arguments.callee.caller != null) {
  611.           msg = msg + "in " 
  612.                 + this.GetFunctionName(arguments.callee.caller)
  613.                 + ")";
  614.         }
  615.         msg = msg + "\n" + this.StackTrace();
  616.         updater.console.println(msg);
  617.       }
  618.     },
  619.  
  620.  
  621.     //
  622.     // convert a string in generalized ASN1 time format to JS Date Object
  623.     // returns null if conversion failed.  (it only support UTC as timezone.
  624.     // cannot convert between timezones yet)
  625.     // 
  626.     // eg:
  627.     // http last mod date:
  628.     // Date: Thu, 07 Nov 2002 10:09:38 GMT
  629.     // GEN_ASN1 eg1:
  630.     // "20021107061101Z"
  631.     //  012345678901234
  632.     // 
  633.     // GEN_ASN1 eg2:
  634.     // "20021107061101.27Z"
  635.     // 
  636.     // GEN_ASN1 eg3:
  637.     // "20021107061101.27-0200"
  638.     //
  639.     GenASN1ToDate: function (str) {
  640.  
  641.       var year, month, day, hours, mins, secs, ms, timezone;
  642.       var timeStr = new String(str);
  643.  
  644.       // has to be at least 14 or more chars
  645.       if (timeStr.length < 14) { return null; }
  646.  
  647.       year  = timeStr.substring(0 , 4);
  648.       month = timeStr.substring(4 , 6);
  649.       // zero based month used in JS Date
  650.       month = month - 1;
  651.       day   = timeStr.substring(6 , 8);
  652.       hours = timeStr.substring(8 , 10);
  653.       mins  = timeStr.substring(10, 12);
  654.       secs  = timeStr.substring(12, 14);
  655.  
  656. //       updater.console.println(year);
  657. //       updater.console.println(month);
  658. //       updater.console.println(day);
  659. //       updater.console.println(hours);
  660. //       updater.console.println(mins);
  661. //       updater.console.println(secs);
  662.  
  663.       
  664.       // if more than 14 chars, ms and/or timezone may be present
  665.       ms = 0; 
  666.       timezone = "Z";
  667.  
  668.       if (timeStr.length > 14) {
  669.         var plus, minus, zee, dot;
  670.         dot =  timeStr.indexOf(".", 14);
  671.         plus = timeStr.indexOf("+", 14);
  672.         minus = timeStr.indexOf("-", 14);
  673.         zee = timeStr.indexOf("Z", 14);
  674.  
  675. //         updater.console.println("dot = " + dot);        
  676. //         updater.console.println("plus = " + plus);
  677. //         updater.console.println("minus = " + minus);
  678. //         updater.console.println("zee = " + zee);
  679.  
  680.         // check if . exists, if so, try parse ms
  681.         //
  682.         // FIXME: ms parsing is NOT correct here....
  683.         // 0.5 should really be 500 ms, rather than 5 here.
  684.  
  685.         // must compare >= 0 to force numeric comparison instead of lexical
  686.         if (dot >= 0) {
  687.           if (zee >= 0) { ms = timeStr.substring( dot + 1, zee); }
  688.           else if (plus >= 0) { ms = timeStr.substring( dot + 1, plus); }
  689.           else if (minus >= 0) { ms = timeStr.substring( dot + 1, minus); } 
  690.           else { ms = 0; }
  691.         }
  692.  
  693. //        updater.console.println(ms);
  694.  
  695.         if (zee >= 0) { timezone = "Z"; }
  696.         else if (plus >= 0) { timezone = timeStr.substring( plus, plus + 5); }
  697.         else if (minus >= 0 ) { timezone = timeStr.substring( minus, minus + 5); }
  698.         else { timezone = "Z"; }
  699.  
  700. //        updater.console.println("timezone = " + timezone);
  701.       }
  702.  
  703.       //updater.console.println("returning");
  704.       return new Date(Date.UTC(year, month, day, hours, mins, secs, ms));
  705.     },
  706.  
  707.     // replace as many %s in str with replacements in array in order
  708.     ReplacePrintfToken: function(str, array) {
  709.       if (array.constructor != Array || array.length == 0) return str;
  710.       if (str.constructor != String || str.length == 0) return str;
  711.  
  712.       var token = "%s";
  713.       for (var i = 0; i < array.length; i++) {
  714.         str = str.replace(token, array[i]);
  715.         }
  716.       
  717.       return str;
  718.     },
  719.  
  720.     // 
  721.     // return Date Object
  722.     // the first update time is 25 + [1-10] days from now
  723.     CreateFirstUpdateTime: function()
  724.     {
  725.         var t = new Date(); // current time in UTC
  726.         var fuss = ((Math.random() * 7) + 28) * (1000 * 60 * 60 * 24); // in ms
  727.         var ms = t.getTime();
  728.         ms += fuss;
  729.         var first = new Date(ms);
  730.         // updater.console.println("now = " + t);
  731.         // updater.console.println("next = " + next);
  732.  
  733.         return first;
  734.     },
  735.  
  736.     isTimeToUpdate: function()
  737.     {
  738.       // define nextCheckDate
  739.       // updater.console.println("isTimeToUpdate()");
  740.  
  741.         if (!this.PropertyIsDefined(updater, "nextCheckDate")) {
  742.           //updater.console.println("nextCheckDate not defined; define it now");
  743.           updater.nextCheckDate = this.CreateFirstUpdateTime();
  744.           updater.console.println("nextCheckDate = " + updater.nextCheckDate);          }
  745.  
  746.         //return true;
  747.  
  748.         var now = new Date();
  749.  
  750.         if (now.getTime() > updater.nextCheckDate.getTime()) {
  751.             updater.console.println("-->It is time to do auto update");
  752.             return true;
  753.         } else {
  754.             updater.console.println("-->It is NOT time to do auto update yet.  will check on:");
  755.             updater.console.println(updater.nextCheckDate);
  756.             return false;
  757.         }
  758.     },
  759.  
  760.     advanceNextCheckDate: function()
  761.     {
  762.         updater.console.println("advanceNextCheckDate()");
  763.         var next_ms = updater.nextCheckDate.getTime() +  30 * (1000 * 60 * 60 * 24); // in ms
  764.         var later = new Date(next_ms);
  765.         updater.nextCheckDate = later;
  766.     },
  767.  
  768.     loadState: function()
  769.     {
  770.       updater.console.println("updater loading store");
  771.       try {
  772.         updater.store.load();
  773.         }
  774.       catch (e) {
  775.         updater.console.println("Exception in loadState(): " + e);
  776.         updater.console.println("  --> skip loading store");
  777.         }
  778.       // updater.console.println("..loading nextCheckDate");
  779.       if (this.PropertyIsDefined(updater.store.perUser, "nextCheckDate")) {
  780.         updater.nextCheckDate = new Date(Date.parse(updater.store.perUser.nextCheckDate));
  781.         updater.console.println(".. nextCheckDate = " + updater.nextCheckDate);
  782.         }
  783.       
  784.       // viewed messages
  785.       //updater.console.println("..loading viewedMessages");
  786.       if (this.PropertyIsDefined(updater.store.perUser, "viewedMessages")) {
  787.         updater.viewedMessages = updater.store.perUser.viewedMessages;
  788.         //this.DumpObject(updater.viewedMessages);
  789.         }
  790.       else {
  791.         updater.viewedMessages = {};
  792.         }
  793.     },
  794.  
  795.     
  796.     saveState: function()
  797.     {
  798.       updater.console.println("updater saving store");
  799.       //updater.console.println("..saving nextCheckDate");
  800.       if (this.PropertyIsDefined(updater, "nextCheckDate")) {
  801.         updater.store.perUser.nextCheckDate = updater.nextCheckDate.toUTCString();
  802.         //updater.console.println("..saving nextCheckDate ok");
  803.         }
  804.           
  805.       //updater.console.println("..saving viewedMessages");
  806.       if (this.PropertyIsDefined(updater, "viewedMessages")) {
  807.         updater.store.perUser.viewedMessages = updater.viewedMessages;
  808.         //this.DumpObject(updater.viewedMessages);
  809.         //updater.console.println("..saving viewedMessages ok");
  810.         }
  811.  
  812.       try {
  813.         updater.store.save();
  814.         }
  815.       catch (e) {
  816.         updater.console.println("Exception in saveState(): " + e);
  817.         throw new Error("SaveStateException");
  818.         }
  819.     },
  820.  
  821.     // will pop up a dialog warning user if no net connection is found
  822.     checkNetConnection: function(skipUI) 
  823.     {
  824.       var hasNet; 
  825.       if ( typeof(updater.net["isConnected"]) != "undefined") {
  826.         hasNet = updater.net.isConnected();
  827.         }
  828.       else {
  829.         hasNet = updater.dlm.hasNetAccess();
  830.         }
  831.       
  832.       if (!hasNet && !skipUI) {
  833.         var title = updater.app.getUpdaterString("bsJSNoNetConnectTitle");
  834.         var errMsg = updater.app.getUpdaterString("bsJSNoNetConnectText");
  835.         updater.app.alert({nIcon:0, nType:0, cTitle:title, cMsg:errMsg});
  836.         return false;
  837.       }
  838.       else {
  839.         return true;
  840.       }
  841.     },
  842.  
  843.  
  844.     // dialog for missing component
  845.     showMissingCompDialog: function(cName) {
  846.       var text;
  847.       var title = updater.app.getUpdaterString("csJSMissCompTitle");
  848.       
  849.       if (!cName || cName.length == 0) {
  850.         text = updater.app.getUpdaterString("csJSMissCompText");
  851.         }
  852.       else {
  853.         text = updater.MasterScript.ReplacePrintfToken(updater.app.getUpdaterString("csJSMissCompTextName"),
  854.                                                        [cName]);
  855.         }
  856.       return updater.app.alert({nIcon:2, nType:2, cTitle:title, cMsg:text});
  857.     },
  858.  
  859.     wellKnownCompDesc: {
  860.       "Plugin/EBook" : function() {
  861.         return updater.app.getUpdaterString("IDS_SAI_EBOOK_NAME");
  862.       },
  863.       
  864.       "Plugin/MultiMedia": function() { 
  865.         return updater.app.getUpdaterString("IDS_SAI_MULTIMEDIA_NAME");
  866.       },
  867.       
  868.       "Plugin/PictureTasks": function() { 
  869.         return updater.app.getUpdaterString("IDS_SAI_MULTIMEDIA_NAME");
  870.       },
  871.  
  872.       "Annot/Screen": function() { 
  873.         return updater.app.getUpdaterString("IDS_SAI_MULTIMEDIA_NAME");
  874.       },
  875.  
  876.       "Annot/Movie": function() { 
  877.         return updater.app.getUpdaterString("IDS_SAI_MULTIMEDIA_NAME");
  878.       },
  879.  
  880.       "AsianFont/TChn": function() { 
  881.         return updater.app.getUpdaterString("IDS_SAI_ASIANFONT_CHT_NAME");
  882.       },
  883.  
  884.       "AsianFont/SChn": function() { 
  885.         return updater.app.getUpdaterString("IDS_SAI_ASIANFONT_CHS_NAME");
  886.       },
  887.  
  888.       "AsianFont/Japn": function() { 
  889.         return updater.app.getUpdaterString("IDS_SAI_ASIANFONT_JPN_NAME");
  890.       },
  891.       
  892.       "AsianFont/Kore": function() { 
  893.         return updater.app.getUpdaterString("IDS_SAI_ASIANFONT_KOR_NAME");
  894.       }
  895.       },
  896.  
  897.     // First look up in updater.wellKnownCompDesc (maybe updated by
  898.     // CodeScipt) if missing, then look up in
  899.     // updater.MasterScript.wellKnownCompDesc (the default list)
  900.     // returns a non zero length string if desc is known and found for comp
  901.     lookUpWellKnownCompDesc: function(type, name) {
  902.       var l;
  903.       var key = type + "/" + name;
  904.       if (updater.MasterScript.PropertyIsDefined(updater, "wellKnownCompDesc")) {
  905.         updater.console.println("  using updater.wellKnownCompDesc");
  906.         l = updater.wellKnownCompDesc;
  907.         }
  908.       else {
  909.         updater.console.println("  using updater.MasterScript.wellKnownCompDesc"); 
  910.         l = updater.MasterScript.wellKnownCompDesc;
  911.         }
  912.       if (! updater.MasterScript.PropertyIsDefined(l, key) ) {
  913.         updater.console.println("  cannot find prop " + key);
  914.         return null;
  915.         }
  916.       if (l[key].constructor == Function) {
  917.         try {
  918.           updater.console.println("  calling " + key + " as function");
  919.           return l[key].call();
  920.           }
  921.         catch (e) {
  922.           updater.console.println("Exception calling wellKnownCompDesc." + key);
  923.           return null;
  924.           }
  925.         }
  926.       else 
  927.         return l[key];
  928.     },
  929.  
  930.     // MasterScript Entry Point
  931.     // app.findComponent()
  932.     findComponent: function(type, name, desc, ver, params)
  933.     {
  934.       try {
  935.         return this.FindComponentAsync(type, name, desc, ver, params);
  936.         }
  937.       catch (e) {
  938.         updater.console.println("exception in findComponent: " + e);
  939.         return false;
  940.         }
  941.     },
  942.  
  943.     // MasterScript Entry Point
  944.     //   this is called by the idle proc
  945.     CheckDLMState: function()
  946.     {
  947.       try {
  948.         updater.MasterScript.asset(false, "CheckDLMState is obsoleted and should not be called.  DLM state checking is now done by AutoUpdateAsync");
  949.         return;
  950.         }
  951.       catch (e) {
  952.         updater.console.println("exception in CheckDLMState: " + e);
  953.         }
  954.     },
  955.  
  956.  
  957.     // find out which message-only notification user has not read and pop up
  958.     // modal dialogs
  959.     popNotifications: function()
  960.     {
  961.       try {
  962.         updater.console.println("  MasterScript popNotifications()");
  963.  
  964.         if ( ! this.init(true) ) return;
  965.  
  966.         updater.console.println("popNotifications()");
  967.  
  968.         // since called AFTER doUpdate(), just need to check if required
  969.         // scripts exist. also, check user pref. if so, pop new notifications
  970.         var notiEnable = updater.avpref.get("Updater", "ShowNotifDialog", 
  971.                                             updater.avpref.type["Boolean"], true);
  972.         // bail out if user doesn't want to see notifications
  973.         if (!notiEnable) { return; }
  974.         
  975.         var hasAllScripts = updater.MasterScript.getAllScriptsFromStore();
  976.  
  977.         updater.console.println("notiEnable = " + notiEnable);
  978.         updater.console.println("hasAllScripts = " + hasAllScripts);
  979.         if (notiEnable && hasAllScripts) {
  980.           updater.DataScript.entryPoint({func:"popNotifications", args:{}});
  981.           }
  982.         updater.console.println("popNotifications() Done");
  983.         }
  984.       catch (e) {
  985.         updater.console.println("exception in popNotifications: " + e);
  986.         return false;
  987.         }
  988.     },
  989.  
  990.     // URL utils
  991.     urlGetProgUI: {
  992.       cancelled: false,
  993.       initialize: function(dialog) 
  994.         {
  995.           currentDialog = dialog;
  996.           this.cancelled = false;
  997.         },
  998.       commit: function(dialog) {},
  999.       close: function()
  1000.         {
  1001.           if(currentDialog)
  1002.             {
  1003.             currentDialog.end();
  1004.             return true;
  1005.             } else return false;
  1006.         },
  1007.       "cncl": function(dialog) {
  1008.         updater.console.println("  cancelled progress dialog");
  1009.         this.cancelled = true;
  1010.         this.close();
  1011.       },
  1012.       description: {
  1013.         name: updater.app.getUpdaterString("msJSChkForUpdtTitle"),
  1014.         elements:
  1015.         [
  1016.             {
  1017.             type: "view",
  1018.             align_children: "align_left",
  1019.             elements: [
  1020.                 {
  1021.                 type: "static_text",
  1022.                 name: updater.app.getUpdaterString("msJSChkForUpdtText"),
  1023.                 alignment: "align_center",
  1024.                 width: 200
  1025.                 },
  1026.                 {
  1027.                 type: "view",
  1028.                 alignment: "align_fill",
  1029.                 align_children: "align_fill",
  1030.                 elements:[
  1031.                     {
  1032.                     type: "button",
  1033.                     item_id: "cncl",
  1034.                     name: updater.app.getUpdaterString("msJSChkForUpdtCancel"),
  1035.                     alignment: "align_center"
  1036.                     }
  1037.                   ]
  1038.                 }
  1039.               ]
  1040.             }
  1041.         ]
  1042.       }
  1043.     },
  1044.  
  1045.     urlMonTask: function()
  1046.     {
  1047.       try {
  1048.         updater.console.println("enter gURLMonTask");
  1049.         var mon = updater.gURLMon;
  1050.         if (! mon.done) { 
  1051.           updater.console.println("     gURLMonTask waits...");
  1052.           mon.wait();
  1053.         }
  1054.         else {
  1055.           updater.console.println("     gURLMonTask got all...");
  1056.          if (updater.gURLMonTask) {
  1057.             updater.app.clearInterval(updater.gURLMonTask);
  1058.             updater.gURLMonTask = null;
  1059.            }
  1060.          updater.MasterScript.urlGetProgUI.close();
  1061.         }
  1062.         updater.console.println("exit gURLMonTask");
  1063.         }
  1064.       catch (e) {
  1065.         if (updater.gURLMonTask) {
  1066.           updater.app.clearInterval(updater.gURLMonTask);
  1067.           updater.gURLMonTask = null;
  1068.           }
  1069.         updater.MasterScript.urlGetProgUI.close();
  1070.         updater.console.println("Exception in URLMonTask" + e);
  1071.       }
  1072.     },
  1073.  
  1074.     // ifModSinceDate: js Date obj
  1075.     urlGetAsyncJSUI: function(url, ifModSinceDate)
  1076.     {
  1077.       updater.console.println("Enter urlGetAsyncUI");
  1078.       if (updater.gURLMonTask || updater.gURLMon ) {
  1079.         updater.console.println("gURLMonTask or gURLMon non-null! throwing...");
  1080.         throw new Error("Fatal error: urlGetAsyncUI is in progress!!");
  1081.       }
  1082.  
  1083.       var taskStr = "updater.MasterScript.urlMonTask();";
  1084.       
  1085.       updater.console.println("--- Added IdleProc");
  1086.       if (ifModSinceDate) {
  1087.         updater.gURLMon = updater.net.urlGetAsync(url, ifModSinceDate.toUTCString());
  1088.       }
  1089.       else {
  1090.         updater.gURLMon = updater.net.urlGetAsync(url);
  1091.       }
  1092.       updater.gURLMonTask = updater.app.setInterval(taskStr, 1000);
  1093.       updater.gURLMon.wait();
  1094.       updater.app.execDialog(this.urlGetProgUI);
  1095.  
  1096.       if ( this.urlGetProgUI.cancelled ) {
  1097.         if (updater.gURLMonTask) {
  1098.           updater.app.clearInterval(updater.gURLMonTask);
  1099.           updater.gURLMonTask = null;
  1100.         }
  1101.         updater.gURLMon.cancel();
  1102.         updater.gURLMon = null;
  1103.  
  1104.         updater.console.println("urlGetAyncUI cancelled!  throwing...");
  1105.         throw new Error("urlGetAyncUI cancelled");
  1106.       }
  1107.       var resp = updater.gURLMon.response;
  1108.  
  1109.       updater.gURLMonTask = null;
  1110.       updater.gURLMon = null;
  1111.  
  1112.       updater.console.println("Exit urlGetAsyncUI");
  1113.       updater.console.println(" http response status = " + resp["Status"]);
  1114.       return resp;
  1115.     },
  1116.  
  1117.     // ifModSinceDate: js Date obj
  1118.     // use blocking updater.net.urlGet
  1119.     urlGetUI: function(url, ifModSinceDate, closeUI)
  1120.     {
  1121.       updater.console.println("Enter urlGetUI");
  1122.  
  1123.       // for backward compatibility
  1124. //       if ( !this.PropertyIsDefined(updater.app, "showProgressDialog") ) {
  1125. //         var resp;
  1126. //         if (ifModSinceDate) {
  1127. //           updater.console.println(" -- pt 1 ");          
  1128. //           resp = updater.net.urlGet(url, ifModSinceDate.toUTCString());
  1129. //           this.DumpObject(ifModSinceDate);
  1130. //           updater.console.println(" -- pt 2 "); 
  1131. //         }
  1132. //         else {
  1133. //           resp = updater.net.urlGet(url);
  1134. //         }
  1135. //         return resp;
  1136. //       }
  1137.  
  1138.       // new
  1139.       if (!updater.isAutoUpdate) {
  1140.         updater.app.showProgressDialog();
  1141.       }
  1142.       updater.app.processDialogEvent();
  1143.  
  1144.       var resp;
  1145.       if (ifModSinceDate) {
  1146.         updater.console.println(" start urlGet() using if-mod-since");
  1147.         resp = updater.net.urlGet(url, ifModSinceDate.toUTCString());
  1148.         updater.console.println(" done urlGet()");
  1149.         }
  1150.       else {
  1151.         updater.console.println(" start urlGet()");
  1152.         resp = updater.net.urlGet(url);
  1153.         updater.console.println(" done urlGet()"); 
  1154.         }
  1155.  
  1156.       updater.app.processDialogEvent();
  1157.       if (closeUI) {
  1158.         updater.app.hideProgressDialog();
  1159.         }
  1160.  
  1161.       // this.DumpObject(resp);
  1162.  
  1163.       if ( updater.app.isProgressDialogCancelled() ) {
  1164.         throw new Error("ProgressDialog Cancelled");
  1165.         }
  1166.       
  1167.       updater.console.println("Exit urlGetUI");
  1168.       return resp;
  1169.     },
  1170.  
  1171.  
  1172.     // ifModSinceDate: js Date obj
  1173.     // use Async updater.net.urlGetAsync
  1174.     urlGetAsyncUI: function(url, ifModSinceDate, closeUI)
  1175.     {
  1176.       updater.console.println("Enter urlGetUIAsync");
  1177.  
  1178.       // new
  1179.       // updater.isAutoUpdate is a gloabl
  1180.       if (! updater.isAutoUpdate) {
  1181.         updater.app.showProgressDialog();
  1182.       }
  1183.  
  1184.       var mon;
  1185.       if (ifModSinceDate) {
  1186.         updater.console.println(" calls updater.net.urlGetAsync() using if-mod-since");
  1187.         mon = updater.net.urlGetAsync(url, ifModSinceDate.toUTCString());
  1188.         }
  1189.       else {
  1190.         updater.console.println(" calls updater.net.urlGetAsync()");
  1191.         mon = updater.net.urlGetAsync(url);
  1192.         }
  1193.  
  1194.       // loop for waiting for async get
  1195.       updater.console.println(" start looping url mon");
  1196.       while (! mon.done) {
  1197.         //updater.console.println("  ...waiting mon");
  1198.         updater.app.processDialogEvent();
  1199.         mon.wait();
  1200.         updater.app.processDialogEvent();
  1201.         if ( updater.app.isProgressDialogCancelled() ) {
  1202.           updater.console.println("  ...cancelling mon");
  1203.           mon.cancel(); 
  1204.           // updater.app.processDialogEvent();
  1205.           updater.app.hideProgressDialog();
  1206.           throw "URLGetCancelled";
  1207.           }
  1208.         }
  1209.       if (closeUI) {
  1210.         updater.app.hideProgressDialog();
  1211.         }
  1212.  
  1213.       var resp = mon.response;
  1214.  
  1215.       updater.console.println("Exit urlGetUIAsync");
  1216.       return resp;
  1217.     },
  1218.  
  1219.     //
  1220.     // FixUp the cacheScriptName so that it is product and language
  1221.     // dependent
  1222.     // eg: cachedMasterScript -> cachedMasterScript_Exchange-Pro_JPN
  1223.     //     cachedDataScript -> cachedDataScript_Reader_FRA
  1224.     //
  1225.     FixUpCacheScriptName: function(str) {
  1226.       var ret = str + "_" + updater.app.viewerType + "_" + updater.app.language;
  1227.       return ret;
  1228.     },
  1229.     // 
  1230.     // updater.tmp
  1231.     // updater.MasterScript
  1232.     // updater.DataScript
  1233.     // updater.CodeScript
  1234.     // updater.UIScript
  1235.     //
  1236.  
  1237.     //
  1238.     // updater.store.perUser:
  1239.     //   cachedMasterScript = { cachedDate: Date, scriptObj: script };
  1240.     //   cachedDataScript
  1241.     //   cachedCodeScript
  1242.     //   cachedUIScript
  1243.     //   nextCheckDate
  1244.     // 
  1245.     // CachedScript obj is like { cachedDate: Date, scriptObj: script };
  1246.     //
  1247.     
  1248.     // The input scriptCacheName are cachedMasterScript, cachedDataScript,
  1249.     // cachedCodeScript, cachedUIScript, etc.
  1250.     // 
  1251.     // scriptCacheName are postpended with prodConfig and Lang:
  1252.     // eg: cachedMasterScript -> cachedMasterScript_Exchange-Pro_JPN
  1253.     //     cachedDataScript -> cachedDataScript_Reader_FRA
  1254.     //
  1255.     // the postpended names are the actually names used in udstore.js
  1256.     //
  1257.     GetCachedScriptObj: function(serializationRoot, // updater.store.perUser
  1258.                                  scriptCacheName) // cachedDataScript, name for a CachedScript obj
  1259.     {
  1260.       updater.console.println("  GetCachedScriptObj()");
  1261.       var cachedScriptObj = null;
  1262.       
  1263.       // Should validate input params here!
  1264.       if (! scriptCacheName || scriptCacheName.length <=0 ) { throw "InvalidCachedName"; };
  1265.       
  1266.       scriptCacheName = this.FixUpCacheScriptName(scriptCacheName);
  1267.       updater.console.println("  scriptCacheName = " + scriptCacheName);
  1268.       
  1269.       // var serializationRoot = updater.store.perUser;
  1270.       
  1271.       // Do we have a cached data script object? If so, grab the date
  1272.       // associated with it.  This represents the moddate (in server-time) of
  1273.       // the data.
  1274.  
  1275.       try {
  1276.         // try finding cachedScriptModDate from presisted script
  1277.         if ( this.PropertyIsDefined(serializationRoot, scriptCacheName) ) {
  1278.  
  1279.           // Looks like we have a cached data script obj.  Just to be safe,
  1280.           // we'll ensure that it has the required keys
  1281.           // var cachedScriptObj = serializationRoot.cachedDataScript;
  1282.           cachedScriptObj = serializationRoot[scriptCacheName];
  1283.  
  1284.           // the cachedScriptObj must have prop scriptObj and cachedData
  1285.           if ( !this.PropertyIsDefined( cachedScriptObj, "scriptObj" ) || !this.PropertyIsDefined( cachedScriptObj, "cachedDate" ) ) {
  1286.             updater.console.println("   corrupted scriptobj");
  1287.             // missing a critical prop! nuke the cache info
  1288.             // delete serializationRoot.cachedDataScript;
  1289.             delete serializationRoot[scriptCacheName];
  1290.             }
  1291.             // else {
  1292.             // setup to use the moddate of the data JS in an if-modified-since query
  1293.             // cachedScriptModDate = new Date(Date.parse(cachedScriptObj.cachedDate));
  1294.             //updater.console.println("  cachedScriptObj.cachedDate = " + cachedScriptModDate);
  1295.             // }
  1296.  
  1297.           // if older version of DataScript < 0.02
  1298.           // updater.console.println("  cachedScript version = " + cachedScriptObj.scriptObj.version);
  1299.           
  1300.           //if (cachedScriptObj.scriptObj.version < "0.02") {
  1301.           //updater.console.println(" has older DataScript.  force loading new one");
  1302.           //cachedScriptModDate = null;
  1303.           //}
  1304.           }
  1305.         }
  1306.       catch (e) {
  1307.         updater.console.println(" exception in finding out cachedScriptModDate ");
  1308.         updater.console.println(" setting cachedScriptModDate to null");
  1309.       }
  1310.       return cachedScriptObj;
  1311.     },
  1312.  
  1313.     GetCachedScriptModDate: function(cachedScriptObj)
  1314.     {
  1315.       updater.console.println("  GetCachedScriptModDate()");
  1316.       var cachedScriptModDate = null; 
  1317.       if ( cachedScriptObj && this.PropertyIsDefined( cachedScriptObj, "cachedDate" ) ) {
  1318.         cachedScriptModDate  = new Date(Date.parse(cachedScriptObj.cachedDate));
  1319.         }
  1320.       return cachedScriptModDate;
  1321.     },
  1322.  
  1323.     // returns a resp obj
  1324.     DownloadScript: function(scriptURL, cachedScriptModDate)
  1325.     {
  1326.       updater.console.println("  DownloadScript()");
  1327.       var resp;
  1328.       try {
  1329.         if (cachedScriptModDate) {
  1330.           updater.console.println("  Using if-mod-since");
  1331.           if (updater.useSyncRead) {
  1332.             resp = this.urlGetUI(scriptURL, cachedScriptModDate);
  1333.             }
  1334.           else {
  1335.             resp = this.urlGetAsyncUI(scriptURL, cachedScriptModDate);
  1336.             }
  1337.           }
  1338.         else {
  1339.           updater.console.println("  NOT Using if-mod-since");
  1340.           if (updater.useSyncRead) {
  1341.             resp = this.urlGetUI(scriptURL);
  1342.             }
  1343.           else {
  1344.             resp = this.urlGetAsyncUI(scriptURL);
  1345.             }
  1346.           }
  1347.         }
  1348.       catch (e) {
  1349.         if (e == "URLGetCancelled") {
  1350.           throw "DownloadCancelled";
  1351.         }
  1352.         updater.console.println("Exception raised from updater.net.urlGet() or urlGetAsync() - " + e);
  1353.         updater.app.hideProgressDialog();
  1354.         throw "URLGetException";
  1355.         }
  1356.       return resp;
  1357.     },
  1358.  
  1359.     // return a scriptObj 
  1360.     GetAndCacheScriptObjFromResp: function(cachedScriptObj, resp, 
  1361.                                            serializationRoot, scriptCacheName)
  1362.     {
  1363.       updater.console.println("  GetAndCacheScriptObjFromResp()");
  1364.       scriptCacheName = this.FixUpCacheScriptName(scriptCacheName);
  1365.       updater.console.println("  scriptCacheName = " + scriptCacheName);
  1366.  
  1367.       // If we succesfully downloaded the data script, or if we got a not-modified result, we need to grab the
  1368.       // date returned by the server, which we'll use as our new last-check date.  This avoids clock skew
  1369.       // between the local machine and the server.
  1370.       var serverDate = null;
  1371.  
  1372.       updater.console.println("  checking response status");
  1373.       if (!resp || ! this.PropertyIsDefined(resp, "Status")) {
  1374.         updater.app.hideProgressDialog();
  1375.         throw "NoReponseStatus";
  1376.       }
  1377.  
  1378.       updater.console.println("  http response status = " + resp["Status"]);
  1379.  
  1380.       // if-modified-since case
  1381.       if (resp["Status"] == 304) {
  1382.         updater.console.println("  if-mod-since used since server response status = " + resp["Status"]);
  1383.         // used the cached datascript
  1384.         // updater.DataScript = cachedScriptObj.scriptObj;
  1385.         return cachedScriptObj.scriptObj;
  1386.         }
  1387.  
  1388.       // all other server error
  1389.       if (resp["Status"] != 200) {
  1390.         updater.app.hideProgressDialog();          
  1391.         throw "ServerError";
  1392.         }
  1393.  
  1394.       // Status = 200
  1395.       updater.console.println("  got newer content from server");
  1396.       // updater.console.println("resp.Content = " + resp.Content.substr(0, 30));
  1397.       // Get rid of the old cached data since it is out of date
  1398.       // delete serializationRoot.cachedDataScript;
  1399.       delete serializationRoot[scriptCacheName];
  1400.       
  1401.       if ( this.PropertyIsDefined( resp.Headers, "Date" ) ) {
  1402.         serverDate = this.GenASN1ToDate( resp.Headers["Date"] );
  1403.         updater.console.println("  Got Server Date ");
  1404.         }
  1405.       else {
  1406.         // illegal HTTP response without a Date header!
  1407.         updater.console.println("  illegal HTTP response without a Date header!  throw!");
  1408.         updater.app.hideProgressDialog();
  1409.         throw "NoDateHeader";
  1410.         }
  1411.  
  1412.       // Get the new moddate for the downloaded data out of the HTTP response headers.  Per HTTP 1.1 spec
  1413.       // section 14.25, we'll first try to get the Last-Modified header.  Failing this, we'll use the value
  1414.       // of the date header (which we retrieved above and stored in serverDate)
  1415.       var newModDate;
  1416.       if ( this.PropertyIsDefined( resp.Headers, "Last-Modified" ) ) {
  1417.         updater.console.println("  using Last-Modified to cache");
  1418.         newModDate = this.GenASN1ToDate( resp.Headers["Last-Modified"] );
  1419.         }
  1420.       else {
  1421.         updater.console.println("  using serverDate to cache");
  1422.         newModDate = serverDate;
  1423.         }
  1424.       updater.console.println("  newModDate = " + newModDate);
  1425.       
  1426.       // eval the returned data.  If this pukes, it'll throw.  We'll put in a check for null as well
  1427.       // just to be paranoid
  1428.       updater.console.println("  Eval resp.Content ");
  1429.       var newScriptObj = eval( resp.Content );
  1430.       if ( newScriptObj == null ) {
  1431.         updater.console.println("  Something wrong while eval resp.Content.  throws!");
  1432.         updater.app.hideProgressDialog();
  1433.         throw "BadData";
  1434.         }
  1435.         
  1436.       // Put the new cached data where it belongs
  1437.       updater.console.println("  Caching Content");
  1438.       // serializationRoot.cachedDataScript = { cachedDate : newModDate, scriptObj : newScriptObj };
  1439.       serializationRoot[scriptCacheName] = { cachedDate : newModDate, scriptObj : newScriptObj };
  1440.       
  1441.       // updater.DataScript = newScriptObj;
  1442.       return newScriptObj;
  1443.     },
  1444.  
  1445.     // return scriptObj
  1446.     downloadAndCacheScript: function(scriptURL,
  1447.                                      serializationRoot, // updater.store.perUser
  1448.                                      scriptCacheName // cachedDataScript, name for a CachedScript obj
  1449.                                      ) {
  1450.  
  1451.       if (! scriptURL || scriptURL.length <=0 ) { throw "InvalidScriptURL"; };
  1452.       updater.console.println("===== downloadAndCacheScript =====");
  1453.       updater.console.println("   url = " + scriptURL);
  1454.  
  1455.       var cachedScriptObj = null;
  1456.       cachedScriptObj = this.GetCachedScriptObj(serializationRoot, scriptCacheName);
  1457.  
  1458.       var cachedScriptModDate = null;
  1459.       cachedScriptModDate = this.GetCachedScriptModDate(cachedScriptObj);
  1460.  
  1461.       var resp = null;
  1462.  
  1463.       resp = this.DownloadScript(scriptURL, cachedScriptModDate);
  1464.       
  1465.       var scriptObj = null;
  1466.       scriptObj = this.GetAndCacheScriptObjFromResp(cachedScriptObj, resp, 
  1467.                                                     serializationRoot, scriptCacheName);
  1468.  
  1469.       return scriptObj;
  1470.     },
  1471.  
  1472.  
  1473.     // return a script or null
  1474.     getScriptFromStore: function(serializationRoot, 
  1475.                                  scriptCacheName) {
  1476.       if (updater.MasterScript.PropertyIsDefined(serializationRoot, scriptCacheName)) {
  1477.         updater.console.println("getScriptFromStore got " + scriptCacheName);
  1478.         return serializationRoot[scriptCacheName].scriptObj;
  1479.         
  1480.         }
  1481.       else {
  1482.         updater.console.println("getScriptFromStore returns null ");
  1483.         return null;
  1484.         }
  1485.     },
  1486.  
  1487.     // bring all scripts to runtime from store
  1488.     // only called by popNotifications().
  1489.     // will NOT go to net and fetch latest script
  1490.     // return true if all scripts exist
  1491.     //
  1492.     // TODO: need to check ResourceScript as well 
  1493.  
  1494.     // TODO: even better, if DataScript exist, check it dependency list for
  1495.     // required scripts rather than just code in all scripts names here
  1496.  
  1497.     // FIXME: MUST CALL FixUpCacheScriptName!!! otherwise won't find any scripts
  1498.  
  1499.     getAllScriptsFromStore: function() {
  1500.       updater.console.println(" getAllScriptsFromStore()");
  1501.  
  1502.       if ( ! updater.MasterScript.PropertyIsDefined(updater, "DataScript")) {
  1503.         var ret = updater.MasterScript.getScriptFromStore(updater.store.perUser, 
  1504.                                                           this.FixUpCacheScriptName("cachedDataScript"));
  1505.         if (ret != null) { 
  1506.           updater.DataScript = ret; 
  1507.           }
  1508.         else { 
  1509.           updater.console.println("   missing from store - DataScript");
  1510.           return false; 
  1511.           }  // if DataScript not in store, other script cannot be
  1512.       }
  1513.  
  1514.       updater.MasterScript.assert(updater.DataScript, "update.DataScript undefined");
  1515.  
  1516.       updater.console.println("   got from store - DataScript");
  1517.  
  1518.       var depList = updater.DataScript.GetScriptDependency();
  1519.       updater.MasterScript.assert(depList.constructor == Array, "depList not an Array!");
  1520.       var idx = 0;
  1521.       var gotAll = false;
  1522.       updater.console.println("  depList.length = " + depList.length);
  1523.       while ( idx < depList.length ) {
  1524.       updater.console.println("  idx = " + idx);
  1525.  
  1526.         var sRoot = depList[idx]["serializationRoot"]; // updater.store.perUser
  1527.         var sCachName = depList[idx]["scriptCacheName"]; // "cachedCodeScript"
  1528.         var cPoint = depList[idx]["callPoint"]; // "CodeScript"
  1529.         
  1530.         if ( updater.MasterScript.PropertyIsDefined(updater, cPoint) ) {
  1531.           // already defined
  1532.           updater.console.println("   got " + cPoint);
  1533.           idx++;
  1534.           }
  1535.         else {
  1536.           // trying mounting from store
  1537.           var scpt = updater.MasterScript.getScriptFromStore(sRoot, this.FixUpCacheScriptName(sCachName));
  1538.           if (ret != null) { 
  1539.             updater[cPoint] = scpt;
  1540.             idx++;
  1541.             updater.console.println("   got from store - " + cPoint);
  1542.             }
  1543.           else {
  1544.             updater.console.println("   missing from store - " + cPoint);
  1545.             break;
  1546.             }
  1547.           }
  1548.         }
  1549.  
  1550.       if (idx == depList.length) { gotAll = true; };
  1551.       return gotAll;
  1552.     },
  1553.  
  1554.     // Dev Tests
  1555.     
  1556.     getTestMasterURL: function()
  1557.     {
  1558.         var testmaster = "TestMaster.js";
  1559.         var ret = updater.scriptRootURL + testmaster;
  1560.         return ret;
  1561.     },
  1562.  
  1563.  
  1564.     testExec: function()
  1565.     {
  1566.       // this.findComponent("annotation", "bumper sticker");
  1567.       this.popNotifications();
  1568.       
  1569. //       var d1 = "20021107061101Z";
  1570. //       var d2 = "20010315182201.27Z";
  1571. //       var d3 = "20020910213422.56-0200";
  1572.  
  1573. //       var res = updater.MasterScript.GenASN1ToDate(d1);
  1574. //       updater.console.println(" d1 = " + res.toUTCString());
  1575.  
  1576. //       var res = updater.MasterScript.GenASN1ToDate(d2);
  1577. //       updater.console.println(" d1 = " + res.toUTCString());
  1578.  
  1579. //       var res = updater.MasterScript.GenASN1ToDate(d3);
  1580. //       updater.console.println(" d1 = " + res.toUTCString());
  1581.  
  1582. //       return;
  1583.  
  1584.       updater.console.println("Start Updater Test");
  1585.  
  1586.         var testMasterURL = this.getTestMasterURL();
  1587.         var testScript;
  1588.         try {
  1589.           var resp;
  1590.           // resp = this.urlGetAsyncUI(testMasterURL);
  1591.           resp = updater.MasterScript.urlGetUI(testMasterURL, null, true);
  1592.           updater.console.println("  Got TestMaster");
  1593.           updater.TestMaster = eval(resp.Content);
  1594.           updater.console.println("  Eval TestMaster done");
  1595.  
  1596.           if (this.PropertyIsDefined(updater, "TestMaster")) {
  1597.             updater.TestMaster.exec();
  1598.             }
  1599.           else {
  1600.             updater.console.println("  Cannot load TestMaster");
  1601.             }
  1602.         }
  1603.         catch (e) {
  1604.           updater.console.println("exception while fetching TestMaster:  " + e);
  1605.         }
  1606.     },
  1607.  
  1608.     updaterPrefPanelSrc:
  1609.     {
  1610.       version: "0.01",
  1611.  
  1612.       monthlyText : updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATEMONTHLY"),
  1613.       manuallyText : updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATEMANUALLY"),
  1614.  
  1615.       // constants
  1616.       monthly: 1,
  1617.       manually: 0,
  1618.       
  1619.       nextCheckText: updater.app.getUpdaterString("IDS_PREFS_PANEL_NEXTCHECK"),
  1620.       manualNextCheck: updater.app.getUpdaterString("IDS_PREFS_PANEL_MANUALNEXTCHECK"),
  1621.  
  1622.       updateDescText: updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATEDESCTEXT"),
  1623.       updateDescTextReader: updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATEDESCTEXT_READER"),
  1624.       updateAcrobatNowText: updater.app.getUpdaterString("IDS_UPDATE_ACROBAT_NOW"),
  1625.       updateReaderNowText: updater.app.getUpdaterString("IDS_UPDATE_READER_NOW"),
  1626.  
  1627.  
  1628.       hasMsgFunc: function(arg) {
  1629.           updater.console.println("arg.returnVal = " + arg.returnVal);
  1630.           var hasMsg = (arg.returnVal > 0);
  1631.           arg["hasMsg"] = hasMsg;
  1632.           updater.console.println("inner hasMsg = " + hasMsg);
  1633.       },
  1634.  
  1635.       // dsiu: TODO: need to unwind this to CodeScript
  1636.       initialize: function(dialog) {
  1637.         updater.console.println("updaterPrefDialog initialize");
  1638.  
  1639.         // this.l10n_init(dialog);
  1640.  
  1641.         var freq = updater.app.getUpdateFrequency();
  1642.         updater.console.println("  freq = " + freq);
  1643.  
  1644.         var choices = {};
  1645.         if (freq == this.monthly) {
  1646.           updater.console.println("    using monthly");
  1647.           choices[this.monthlyText] = 1;
  1648.           choices[this.manuallyText] = 0;
  1649.           }
  1650.         else {
  1651.           updater.console.println("    using manually");
  1652.           choices[this.monthlyText] = 0;
  1653.           choices[this.manuallyText] = 1;
  1654.           }
  1655.         //dialog.load( { "Freq" : { "Every Month" : (freq == this.monthly) , 
  1656.         //"Manually" : (freq == this.manually) } } );
  1657.         dialog.load( {"Freq" : choices} );
  1658.  
  1659.         // widths 
  1660.         var date;
  1661.         if (freq==this.manually)
  1662.           date = this.manualNextCheck;
  1663.         else
  1664.           {
  1665.           if (!updater.MasterScript.PropertyIsDefined(updater, "nextCheckDate"))
  1666.             {
  1667.             updater.console.println("nextCheckDate not defined; define it now");
  1668.             updater.nextCheckDate = updater.MasterScript.CreateFirstUpdateTime();
  1669.             updater.console.println("nextCheckDate = " + updater.nextCheckDate);
  1670.             }
  1671.         
  1672.           date = "" + updater.nextCheckDate;
  1673.           }
  1674.         dialog.load( { "ckAc" : (date) } );
  1675.  
  1676.         var type = updater.app.viewerType;
  1677.         if ( type == "Reader" ) {
  1678.           dialog.load( { "text" : this.updateDescTextReader } );
  1679.           dialog.load( { "UpAc" : this.updateReaderNowText } );
  1680.           }
  1681.         else {
  1682.           dialog.load( { "text" : this.updateDescText } );
  1683.           dialog.load( { "UpAc" : this.updateAcrobatNowText } );
  1684.           }
  1685.  
  1686.         dialog.load( { "conf" : updater.app.getShowUpdateDialog() } );
  1687.         dialog.load( { "ShNo" : updater.app.getShowStartupNotifDialog() } );
  1688.  
  1689.         // FIXME: 
  1690.         // enable Notification button only when there are messages
  1691.         // downloaded AND not restart pending!
  1692.         var hasAllScripts = updater.MasterScript.getAllScriptsFromStore();
  1693.  
  1694.         hasMsgFuncArgs = { "hasMsg": false };
  1695.  
  1696.         if (hasAllScripts) {
  1697.           updater.DataScript.entryPoint({func: "GetNumMessages", 
  1698.                                          args:{}, callBack: this.hasMsgFunc,
  1699.                                          callBackArgs: hasMsgFuncArgs});
  1700.         };
  1701.  
  1702.         var hasMsg = hasMsgFuncArgs["hasMsg"];
  1703.  
  1704.         updater.console.println("outter hasMsg = " + hasMsg);
  1705.         var notiEnable = hasAllScripts && 
  1706.                          (! updater.MasterScript.checkPendingRestart(true))
  1707.                          && hasMsg;
  1708.  
  1709.         var hasUpsEnable = hasAllScripts &&
  1710.                            (! updater.MasterScript.checkPendingRestart(true));
  1711.                            
  1712.         dialog.enable( { "Noti" : notiEnable } );
  1713.         dialog.enable( { "InUp" : hasUpsEnable });
  1714.         dialog.createNotifier( { "InUp" : 0, "Noti" : 0 } );
  1715.       },
  1716.  
  1717.       // dsiu: TODO: need to unwind this to CodeScript
  1718.       commit: function(dialog) {
  1719.         updater.console.println("updaterPrefDialog commit");
  1720.  
  1721.         // var val = dialog.store("Freq")["Freq"];
  1722.         var val = dialog.store("Freq")["Freq"];
  1723.         var isMan = val[this.manuallyText];
  1724.         var isMonth = val[this.monthlyText];
  1725.  
  1726.         updater.console.println(" isMan = " + isMan);
  1727.         updater.console.println(" isMon  = " + isMonth); 
  1728.  
  1729.         updater.app.setUpdateFrequency(isMan ? this.manually : this.monthly);
  1730.         updater.app.setShowUpdateDialog(dialog.store("conf" )["conf"]);
  1731.         updater.app.setShowStartupNotifDialog(dialog.store("ShNo" )["ShNo"]);
  1732.       },
  1733.  
  1734.       // dsiu: TODO: need to unwind this to CodeScript
  1735.       // manual update
  1736.       // "UpAc": function(dialog) {
  1737.       // updater.console.println("UpAc clicked");
  1738.       // updater.MasterScript.entryPoint(true);
  1739.       // },
  1740.       
  1741.       "InUp": function(dialog) {
  1742.         updater.console.println("InUp clicked");
  1743.         updater.DataScript.entryPoint({func:"ShowInstalledUpdatesDialog", args:{}});        
  1744.       },
  1745.  
  1746.       // dsiu: TODO: need to unwind this to CodeScript
  1747.       "Noti": function(dialog) {
  1748.         updater.console.println("Noti clicked");
  1749.         updater.DataScript.entryPoint({func:"ShowNotifDialog", args:{}});
  1750.       }
  1751.     },
  1752.  
  1753.    // Pref Panel
  1754.    GetUpdaterPrefPanel: function() {
  1755.       var updatePanelName = updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATE");
  1756.       var gStaticTextHeight = 13;
  1757.       var gPrefsPanelWidth = 550;
  1758.       var gPrefsPanelHeight = 390;
  1759.  
  1760.       var updaterPrefPanel = updater.MasterScript.updaterPrefPanelSrc;
  1761.  
  1762.       updaterPrefPanel["description"] = 
  1763.       {
  1764.       name: "Update Prefs Panel",
  1765.       margin_height: "0",
  1766.       margin_width: "0",
  1767.       elements: [
  1768.           {
  1769.           type: "cluster",
  1770.           name: (updatePanelName),
  1771.           dwidth: (gPrefsPanelWidth),
  1772.           dheight: (gPrefsPanelHeight),
  1773.           align_children: "align_left",
  1774.           elements: [
  1775.               {  
  1776.               type: "static_text",
  1777.               item_id: "text",
  1778.               alignment: "align_fill",
  1779.               height: (gStaticTextHeight*5)
  1780.               },
  1781.  
  1782.               {  
  1783.               type: "view",
  1784.               align_children: "align_row",
  1785.               alignment: "align_fill",
  1786.               elements: [
  1787.                   { 
  1788.                   type: "static_text",
  1789.                   item_id: "nctx",
  1790.                   name: (updaterPrefPanel.nextCheckText)
  1791.                   },
  1792.                                 
  1793.                   {
  1794.                   type: "static_text",
  1795.                   item_id: "ckAc",
  1796.                   alignment: "align_fill"
  1797.                   }
  1798.                 ]
  1799.               },
  1800.  
  1801.               {
  1802.               type: "gap",
  1803.               height: (gStaticTextHeight)
  1804.               },
  1805.  
  1806.               {
  1807.               type: "view",
  1808.               align_children: "align_right",
  1809.               alignment: "align_center",
  1810.               elements: [
  1811.                   {
  1812.                   type: "view",
  1813.                   align_children: "align_row",
  1814.                   elements: [
  1815.                       {
  1816.                        type: "static_text",
  1817.                        item_id: "cfut",
  1818.                        alignment: "align_right",
  1819.                        name: (checkForUpdatesText)
  1820.                        },
  1821.                     
  1822.                       {
  1823.                       type: "popup",
  1824.                       item_id: "Freq",
  1825.                       width: (gUpdateNowWidth)
  1826.                       }
  1827.                     ]
  1828.                   },
  1829.  
  1830.                   {
  1831.                   type: "button",
  1832.                   item_id: "Noti",
  1833.                   width: (gUpdateNowWidth),
  1834.                   name: (updateNotificationBtn)
  1835.                   },
  1836.  
  1837.                   {
  1838.                   type: "button",
  1839.                   item_id: "InUp",
  1840.                   width: (gUpdateNowWidth),
  1841.                   name: updater.MasterScript.getPrefPanelLocStr("UIS_INUPS_INSTALLED_UPDATES")
  1842.                   }
  1843.                 ]
  1844.               },
  1845.                         
  1846.               {
  1847.               type: "gap",
  1848.               height: (gStaticTextHeight)
  1849.               },
  1850.             
  1851.               {
  1852.               type: "check_box",
  1853.               item_id: "conf",
  1854.               name: (showConfirmDlgText)
  1855.               },
  1856.             
  1857.               {
  1858.               type: "check_box",
  1859.               item_id: "ShNo",
  1860.               name: (displayStartupNotifDlgText)
  1861.               }
  1862.             ]
  1863.           }
  1864.         ]
  1865.       };
  1866.  
  1867.       return updaterPrefPanel;
  1868.     }, // GetUpdaterPrefPanel
  1869.  
  1870.     // MasterScript Entry Point
  1871.     // called from idle proc
  1872.     InstallPrefPanel: function() 
  1873.     {
  1874.       try {
  1875.         updater.console.println("  MasterScript InstallPrefPanel()");
  1876.         if ( ! this.init(true) ) return;
  1877.  
  1878.         updater.console.println("InstallPrefPanel");
  1879.       
  1880.         if (!updater.prefPanelInstalled) {
  1881.           // var prefd = this.updaterPrefPanel;
  1882.           // var prefd = updater.MasterScript.updaterPrefPanel;
  1883.           // updater.app.createJSPrefsPanel(prefd, "Updates", "Updates");
  1884.           // try using a global off updater 
  1885.           updater.prefPanel = updater.MasterScript.GetUpdaterPrefPanel();
  1886.           updater.app.createJSPrefsPanel(updater.prefPanel, 
  1887.                                          updater.app.getUpdaterString("IDS_PREFS_PANEL_UPDATE"),
  1888.                                          "Updates");
  1889.           updater.prefPanelInstalled = true;
  1890.           updater.console.println("UpdaterPrefPanel installed");
  1891.           }
  1892.         else {
  1893.           updater.console.println("UpdaterPrefPanel already installed");
  1894.           }
  1895.         updater.console.println("InstallPrefPanel Done");
  1896.         return;
  1897.         }
  1898.       catch (e) {
  1899.         updater.console.println("exception in InstallPrefPanel: " + e);
  1900.         }
  1901.     },
  1902.  
  1903.  
  1904.     //
  1905.     // General way of creating a state machine 
  1906.     //
  1907.     SStartStateMachine : function(idleProc, idleArgs, 
  1908.                                   resumeProc, resumeArgs, 
  1909.                                   name, states)
  1910.     {
  1911.       if (this.PropertyIsDefined(updater, "gStateMachineLock") &&
  1912.           updater.gStateMachineLock == true) {
  1913.         updater.console.println("SStartStateMachine locked by " + 
  1914.                                 updater.gStateMachine.name);
  1915.         throw "StateMachineInUse";
  1916.         }
  1917.       
  1918.       updater.gStateMachineLock = true;
  1919.  
  1920.       // TODO: add singleton
  1921.       updater.gStateMachine = new Object();
  1922.       var sm = updater.gStateMachine;
  1923.  
  1924.       sm.name = name;
  1925.       sm.enumStates = states;
  1926.       sm.state = states.StInit;
  1927.       sm.idleProc = idleProc;
  1928.       sm.idleArgs = idleArgs;
  1929.       sm.resumeProc = resumeProc;
  1930.       sm.resumeArgs = resumeArgs;
  1931.       sm.done = false;
  1932.       sm.error = false;
  1933.       sm.exception = null;
  1934.       // TODO: the interval in ms MUST BE greater than the ADM idle proc
  1935.       // otherwise cancel event won't be received!
  1936.       sm.handle = updater.app.setInterval(idleProc, 60);
  1937.     },
  1938.  
  1939.  
  1940.     // BgDl = Background downloading
  1941.     SBgDlStates : 
  1942.     {
  1943.       StInit: 0,
  1944.       StReadStart: 1,
  1945.       StReadWait: 2,
  1946.       StReadDone: 3,
  1947.       StShowUI: 4,
  1948.       StProcessUI: 5,
  1949.       StException: 800,
  1950.       StFinished: 999
  1951.     },
  1952.  
  1953.     //
  1954.     // This is the state machine for doing download MULTIPLE script, posting
  1955.     // progress dialog, cache script, etc.  this is a replacement for
  1956.     // loadDataScript() / downloadAndCacheScript()
  1957.     //
  1958.     SBgDlProcessState : function()
  1959.     {
  1960.       var sm = updater.gStateMachine;
  1961.  
  1962.       try {
  1963.         var state = sm.state;
  1964.         var st_enum = sm.enumStates;
  1965.         
  1966.         //updater.console.println("= SBgDlProcessState =");
  1967.         //updater.MasterScript.DumpObject(sm.idleArgs, "idleArgs", true);
  1968.  
  1969.         // unpackage the args
  1970.         var loadScriptArgs = sm.idleArgs.loadScriptArgs;
  1971.         updater.MasterScript.assert(loadScriptArgs.constructor == Array, "loadScriptArgs not an Array!");
  1972.  
  1973.         // init idx
  1974.         if (! updater.MasterScript.PropertyIsDefined(sm, "scriptArgIdx") ) {
  1975.           sm.scriptArgIdx = 0;
  1976.           }
  1977.  
  1978.         // updater.console.println("scriptArgIdx = " + sm.scriptArgIdx);
  1979.         // updater.MasterScript.DumpArray(loadScriptArgs);
  1980.  
  1981.         var lsArgs = loadScriptArgs[sm.scriptArgIdx];
  1982.         
  1983.         // cannot check assert here since lsArgs MAYBE null for the last
  1984.         // element before proceeding to the StFinished state
  1985.         //updater.MasterScript.assert(lsArgs, "lsArgs is NULL");
  1986.         // updater.MasterScript.DumpObject(lsArgs, "lsArgs", true);
  1987.  
  1988.         var scriptURL = lsArgs? lsArgs["scriptURL"] : null;
  1989.         var serializationRoot = lsArgs ? lsArgs["serializationRoot"] : null;
  1990.         var scriptCacheName = lsArgs ? lsArgs["scriptCacheName"] : null;
  1991.         var callPoint = lsArgs ? lsArgs["callPoint"] : null;
  1992.         var dontMount = lsArgs ? lsArgs["dontMount"] : null;
  1993.  
  1994.         var suppressUI = sm.idleArgs["suppressUI"];
  1995.         var closeUI = sm.idleArgs["closeUI"];
  1996.  
  1997.         switch (state) {
  1998.           case st_enum.StInit : 
  1999.             try {
  2000.               updater.console.println("=== StInit ===");
  2001.               if (! scriptURL || scriptURL.length <=0 ) { 
  2002.                 sm.exception =  "InvalidScriptURL"; 
  2003.                 sm.state = sm.StException;
  2004.                 break;
  2005.                 }
  2006.               updater.console.println("  url = " + scriptURL);
  2007.               // setup private var in sm
  2008.               sm.cachedScriptObj = null;
  2009.               sm.cachedScriptObj = updater.MasterScript.GetCachedScriptObj(serializationRoot, scriptCacheName);
  2010.               
  2011.               sm.cachedScriptModDate = null;
  2012.               sm.cachedScriptModDate = updater.MasterScript.GetCachedScriptModDate(sm.cachedScriptObj);
  2013.               
  2014.               sm.state = sm.enumStates.StShowUI;
  2015.               }
  2016.             catch (e) {
  2017.               updater.console.println("Exception in StInit: " + e);
  2018.               sm.exception = e;
  2019.               sm.state = sm.StException;
  2020.               }
  2021.             break;
  2022.  
  2023.         case st_enum.StShowUI:
  2024.           try {
  2025.             updater.console.println("=== StShowUI ===");
  2026.             if (!suppressUI) {
  2027.               updater.app.showProgressDialog();
  2028.               }
  2029.             sm.uiCancelled = false;
  2030.             sm.state = sm.enumStates.StReadStart;
  2031.             }
  2032.           catch (e) {
  2033.               updater.console.println("Exception in StShowUI: " + e);
  2034.               sm.exception = e;
  2035.               sm.state = sm.StException;
  2036.             }
  2037.           break;
  2038.           
  2039.         case st_enum.StReadStart :
  2040.           try {
  2041.             updater.console.println("=== StReadStart ===");
  2042.             sm.response = null;
  2043.  
  2044.             if (sm.cachedScriptModDate) {
  2045.               updater.console.println(" calls updater.net.urlGetAsync() using if-mod-since");
  2046.               sm.urlMon = updater.net.urlGetAsync(scriptURL, sm.cachedScriptModDate.toUTCString());
  2047.               }
  2048.             else {
  2049.               updater.console.println(" calls updater.net.urlGetAsync()");
  2050.               sm.urlMon = updater.net.urlGetAsync(scriptURL);
  2051.               }
  2052.             sm.state = sm.enumStates.StProcessUI;
  2053.             }
  2054.           catch (e) {
  2055.             updater.console.println("Exception in StReadStart" + e);
  2056.             sm.exception = "URLGetException";
  2057.             sm.state = sm.enumStates.StException;
  2058.             }
  2059.           break;
  2060.  
  2061.         case st_enum.StProcessUI :
  2062.           try {
  2063.             updater.console.println("=== StProcessUI ===");
  2064.             // updater.app.processDialogEvent();
  2065.             sm.state = sm.enumStates.StUIWait; 
  2066.             }
  2067.           catch (e) {
  2068.               updater.console.println("Exception in StPocessUI: " + e);
  2069.               sm.exception = e;
  2070.               sm.state = sm.StException;            
  2071.             }
  2072.           break;
  2073.  
  2074.         case st_enum.StUIWait :
  2075.           try {
  2076.             updater.console.println("=== StUIWait ===");
  2077.             sm.uiCancelled = updater.app.isProgressDialogCancelled()
  2078.             sm.state = sm.enumStates.StReadWait; 
  2079.             }
  2080.           catch (e) {
  2081.               updater.console.println("Exception in StUIWait: " + e);
  2082.               sm.exception = e;
  2083.               sm.state = sm.StException;            
  2084.             }
  2085.           break;
  2086.               
  2087.         case st_enum.StReadWait :
  2088.           try {
  2089.             updater.console.println("=== StReadWait ===");
  2090.  
  2091.             if (sm.uiCancelled) {
  2092.               sm.urlMon.cancel();
  2093.               sm.exception = "DownloadCancelled";
  2094.               sm.state = sm.enumStates.StException;
  2095.               break;
  2096.               }
  2097.  
  2098.             if (sm.urlMon.done) {
  2099.               sm.state = st_enum.StReadDone;
  2100.               break;
  2101.               }
  2102.  
  2103.             sm.urlMon.wait();
  2104.  
  2105.             sm.state = st_enum.StProcessUI;
  2106.             }
  2107.           catch (e) {
  2108.             updater.console.println("Exception in StReadWait" + e);
  2109.             sm.exception = e;
  2110.             sm.state = sm.enumStates.StException;
  2111.             }
  2112.           break;
  2113.  
  2114.         case st_enum.StReadDone:
  2115.           try {
  2116.             updater.console.println("=== StReadDone ===");
  2117.  
  2118.             // should check again if ui is cancelled due to late click
  2119.             // latching
  2120.             if (updater.app.isProgressDialogCancelled()) {
  2121.               sm.exception = "DownloadCancelled";
  2122.               sm.state = sm.enumStates.StException;
  2123.               break;
  2124.               }
  2125.  
  2126.             if (! updater.MasterScript.PropertyIsDefined(sm, "scriptObjs")
  2127.                 || (sm.scriptObjs.constructor != Array) ) {
  2128.               sm.scriptObjs = new Array();
  2129.               }
  2130.  
  2131.             var idx = sm.scriptArgIdx;
  2132.  
  2133.             // acrobat can raise in urlMon.response if the download scripts
  2134.             // not signed correctly
  2135.             sm.scriptObjs[idx] = 
  2136.                 updater.MasterScript.GetAndCacheScriptObjFromResp(sm.cachedScriptObj, 
  2137.                    sm.urlMon.response, serializationRoot, scriptCacheName);
  2138.  
  2139.             // mount call point
  2140.             if (!dontMount) {
  2141.               updater[callPoint] = sm.scriptObjs[idx];
  2142.               }
  2143.  
  2144.             // initialize script obj
  2145.             if (updater.MasterScript.PropertyIsDefined(updater[callPoint], 
  2146.                                                        "Initialize")
  2147.                 &&
  2148.                 updater[callPoint]["Initialize"].constructor == Function) {
  2149.               updater[callPoint]["Initialize"]();
  2150.               }
  2151.  
  2152.             // done when all script in loadScriptArgs is iterated 
  2153.             sm.scriptArgIdx++;
  2154.             if (sm.scriptArgIdx < loadScriptArgs.length) {
  2155.               sm.state = st_enum.StInit;
  2156.             }
  2157.             else {
  2158.               if (closeUI) {
  2159.                 updater.app.hideProgressDialog();
  2160.                 }
  2161.               sm.state = st_enum.StFinished;
  2162.               }
  2163.             }
  2164.           catch (e) {
  2165.             updater.console.println("Exception in StReadDone : " + e);
  2166.             sm.exception = e;
  2167.             sm.state = sm.enumStates.StException;
  2168.             }
  2169.           break;
  2170.  
  2171.         case st_enum.StException:
  2172.           updater.console.println("=== StException ===");
  2173.           // always closes UI when exception happens
  2174.           updater.app.hideProgressDialog();
  2175.  
  2176.           var e = sm.exception;
  2177.           updater.console.println("Exception in " + sm.name + ": " + e);
  2178.  
  2179.           if (e == "URLGetException" || e == "URLContentNotFound" || e == "ServerError") {
  2180.             // These errors are probably network or server related.  don't
  2181.             // even need to bother user with the error.  just inform them no
  2182.             // update is available at this time
  2183.             var title = updater.app.getUpdaterString("uisJSNoUpdtAvailTitle");
  2184.             var errMsg = updater.app.getUpdaterString("uisJSNoUpdtAvailAtThisTimeText");
  2185.  
  2186.             if (! suppressUI) 
  2187.               updater.app.alert({nIcon:3, nType:0, cTitle:title, cMsg:errMsg});
  2188.             }
  2189.           else if (e == "NoDateHeader" || e == "BadData") {
  2190.             // probably should not pop dialog here since these are internal
  2191.             // errors from downloadAndCacheScript
  2192.             var title = updater.app.getUpdaterString("bsJSNoNetConnectTitle");
  2193.             var errMsg = updater.app.getUpdaterString("bsJSInternalErrorText");
  2194.             
  2195.             if (! suppressUI)
  2196.               updater.app.alert({nIcon:0, nType:0, cTitle:title, cMsg:errMsg});
  2197.             }
  2198.           else if (e == "DownloadCancelled" ) {
  2199.             updater.MasterScript.assert(false, "DownloadCancelled");
  2200.             updater.console.println("DownloadCancelled");
  2201.             // siliently swollow the exception if user cancelled out
  2202.             }
  2203.  
  2204.           sm.exception = "LoadScriptException";
  2205.           sm.state = st_enum.StFinished;
  2206.           break;
  2207.  
  2208.         case st_enum.StFinished:
  2209.           try {
  2210.             updater.console.println("=== StFinished ===");
  2211.             
  2212.             // should check again if ui is cancelled due to late click
  2213.             // latching
  2214.             if (!sm.uiCancelled && updater.app.isProgressDialogCancelled()) {
  2215.               updater.MasterScript.assert(false, "DownloadCancelled");
  2216.               updater.console.println("DownloadCancelled");
  2217.               sm.exception = "LoadScriptException";
  2218.               sm.state = sm.enumStates.StException;
  2219.               }
  2220.  
  2221.             // stop the state machine from advancing and release its lock
  2222.             // since we are done
  2223.             updater.app.clearInterval(sm.handle);
  2224.             sm.done = true;
  2225.             updater.gStateMachineLock = false;
  2226.           
  2227.             // call resume proc when done
  2228.             updater.MasterScript.assert(sm.resumeProc.constructor == Function, "resumeProc NOT a function");
  2229.             if (sm.resumeProc.constructor == Function) {
  2230.               sm.resumeProc(sm);
  2231.               }
  2232.             else {
  2233.               updater.console.println("sm.resumeProc not a function.  skip calling");
  2234.               }
  2235.             }
  2236.           catch (e) {
  2237.             updater.console.println("Exception in StFinished" + e);
  2238.             // close the UI 
  2239.             updater.app.hideProgressDialog();
  2240.             }
  2241.           break;
  2242.           
  2243.         default :
  2244.           updater.MasterScript.assert(false, "Shoule NOT reach default case - " + sm.name);
  2245.           throw "CannotHappen";
  2246.           break;
  2247.           }
  2248.         }
  2249.       catch (e) {
  2250.         sm.exception = e;
  2251.  
  2252.         updater.app.clearInterval(sm.handle);
  2253.         sm.done = true;
  2254.         updater.gStateMachineLock = false;
  2255.  
  2256.         updater.console.println("Exception in SBgDlProcessState: " + e);
  2257.       }
  2258.     },
  2259.  
  2260.     // 
  2261.     // Updater Script loading machinism
  2262.     // 
  2263.     // MasterScript: assumed always available (from bootstrap.js).  it
  2264.     // exports common functions and system functions to all other scripts.
  2265.     // It ONLY knows how to load DataScript.js.  Once DataScript is loaded,
  2266.     // MasterScript inquires DataScript about what other scripts DataScript
  2267.     // needs by calling DataScript.GetScriptDependencyList() and load all the
  2268.     // required scripts.  After each script is loaded, its Initialize()
  2269.     // function will be called if exists.
  2270.     //
  2271.     // DataScript: loaded only by MasterScript.  It has three piece of
  2272.     // information:
  2273.     //
  2274.     // 1) the available component data structure.  it contains all available
  2275.     // component for a given acrobat product configuration.
  2276.     //
  2277.     // 2) messages to be shown by the notification dialog
  2278.     //
  2279.     // 3) A function that returns a script depency list.  This allow future
  2280.     // expandability.  it initially contains only CodeScript and UIScript.
  2281.     //
  2282.     // DataScript Initialize() will have to check if the system has correct
  2283.     // version of MasterScript.  If not, it would call
  2284.     // LoadAndCacheScriptAsync() to get a new MasterScript.  A viewer restart
  2285.     // is required if new MasterScript is loaded.
  2286.     // 
  2287.     // CodeScript: Contains all procedures for doing Auto Update, Manual
  2288.     // Update, FincComponent, etc.
  2289.     //
  2290.     // UIScript: Contains all UI elements for Updater.
  2291.     //
  2292.     // Since MasterScript knows only DataScript, call-chaining is used so
  2293.     // that arbitrary scripts (potentially new scripts) can be used to
  2294.     // implement/replace Updater's functionality.  It works like this:
  2295.     // 
  2296.     // DataScript and the script contains the implementation of Updater's
  2297.     // functionality contains a common entry point, aptly named entryPoint().
  2298.     // it is called with an {} with "func", and "args" memebers.  DataScript
  2299.     // has the right to vector off the requests to the implementation script
  2300.     // (CodeScript) by simply calling entryPoint() with pass the arg along.
  2301.     // MasterScript.AutoUpdate() --> DataScript.entryPoint(arg)
  2302.     // --> CodeScript.entryPoint(arg) --> CodeScript.AutoUpdate(udArgs)
  2303.     // where arg is {func:AutoUpdate, arg:{udArgs}}
  2304.     // udArags is an {}
  2305.     //
  2306.     
  2307.     
  2308.     // 
  2309.     // LoadAndCacheScriptAsync
  2310.     // 
  2311.     // this is a single call for handling all the nasty details regarding
  2312.     // script downloading, mounting, caching, progress UI popping, etc
  2313.     // 
  2314.     // this is a non blocking call.  if suppressUI is true, no UI is shown by
  2315.     // default, the UI is not closed when operation is done unless closeUI is
  2316.     // true.  UI is always closed when exception happens
  2317.     // 
  2318.     // resumeProc will be called with resumeArgs when the script is
  2319.     // downloaded and mounted
  2320.     //
  2321.     // loadScriptArgs is an array of elements:
  2322.     // {
  2323.     //   "scriptURL" : this.getDSURL(),
  2324.     //   "serializationRoot" : updater.store.perUser,
  2325.     //   "scriptCacheName" : "cachedDataScript",
  2326.     //   "callPoint" : "DataScript"
  2327.     //   "dontMount" : false
  2328.     // }
  2329.     //
  2330.     // each element in the loadScriptArgs array will be processed sequentially
  2331.     //
  2332.     LoadAndCacheScriptAsync: function(loadScriptArgs,
  2333.                                       resumeProc, resumeArgs,
  2334.                                       suppressUI, closeUI)
  2335.     {
  2336.       var idleProc =  "updater.MasterScript.SBgDlProcessState()";
  2337.       
  2338.       var idleArgs = { "loadScriptArgs" : loadScriptArgs,
  2339.                        "suppressUI" : suppressUI,
  2340.                        "closeUI" : closeUI };
  2341.                       
  2342.       this.SStartStateMachine(idleProc, idleArgs,
  2343.                               resumeProc, resumeArgs, 
  2344.                               "SBgDlProcessState", this.SBgDlStates);
  2345.       return this.SStartStateMachine;
  2346.     },
  2347.  
  2348.     //
  2349.     // LoadScriptDepFinishProc is called after DataScripts AND its depending
  2350.     // scripts are all downloaded.  The update process continue by 
  2351.     //
  2352.     LoadScriptDepFinishProc: function(sm)
  2353.     {
  2354.       try {
  2355.         updater.console.println("LoadScriptDepFinishProc()"); 
  2356.         // something wrong in state machine, raise it
  2357.         if (sm.exception) { throw sm.exception };
  2358.  
  2359.         updater.MasterScript.assert(sm.resumeArgs["dsCallerResumeProc"], "dsCallerResumeProc undefined! ");
  2360.         
  2361.         updater.app.hideProgressDialog();
  2362.  
  2363.         var func = sm.resumeArgs["dsCallerResumeProc"];
  2364.         var args = sm.resumeArgs["dsCallerResumeArgs"];
  2365.         if (func.constructor == Function) {
  2366.           func(args);
  2367.           }
  2368.         }
  2369.       catch (e) {
  2370.         updater.console.println("Exception in LoadScriptDepFinishProc: " + e);
  2371.         }
  2372.     },
  2373.  
  2374.     //
  2375.     // LoadDataScriptFinishProc is called when DataScript is downloaded.  It
  2376.     // continue the script loading process by using DataScript's script
  2377.     // dependency list.
  2378.     //
  2379.     LoadDataScriptFinishProc: function(sm)
  2380.     {
  2381.       try {
  2382.         updater.console.println("LoadDataScriptFinishProc()"); 
  2383.  
  2384.         // something wrong in state machine, raise it
  2385.         if (sm.exception) { throw sm.exception };
  2386.  
  2387.         var depScriptsArgs = updater.DataScript.GetScriptDependency();
  2388.  
  2389.         // updater.MasterScript.DumpObject(depScriptsArgs,"depScriptsArgs", true);
  2390.  
  2391.         updater.MasterScript.assert(depScriptsArgs.constructor == Array);
  2392.  
  2393.         var suppressUI = sm.resumeArgs["dsCallerSuppressUI"];
  2394.         var closeUI = sm.resumeArgs["dsCallerCloseUI"];
  2395.  
  2396.         updater.MasterScript.LoadAndCacheScriptAsync(depScriptsArgs, 
  2397.                                                      updater.MasterScript.LoadScriptDepFinishProc,
  2398.                                                      sm.resumeArgs,
  2399.                                                      suppressUI, closeUI);
  2400.         }
  2401.       catch (e) {
  2402.         updater.console.println("Exception in LoadDataScriptFinishProc: " + e);
  2403.         }
  2404.     },
  2405.     
  2406.     // 
  2407.     // single call for loading DataScript and its depending scripts used by
  2408.     // AutoUpdateAsync, ManualUpdateAsync, FindComponentAsync, etc
  2409.     //
  2410.     LoadDataScriptAsync: function(resumeProc, resumeArgs, 
  2411.                                   suppressUI, closeUI)
  2412.     {
  2413.       var loadScriptArgs = new Array();
  2414.  
  2415.       var dsLoadArgs = {
  2416.         "scriptURL" : this.getDSURL(),
  2417.         "serializationRoot" : updater.store.perUser,
  2418.         "scriptCacheName" : "cachedDataScript",
  2419.         "callPoint" : "DataScript"
  2420.         };
  2421.       
  2422.       loadScriptArgs[0] = dsLoadArgs;
  2423.  
  2424.       //
  2425.       // remember the orginal caller's resume proc and args so that after all
  2426.       // the DataScript depending are loaded, the update process know where
  2427.       // to continue.
  2428.       // 
  2429.       var dsFinishArg = {"dsCallerResumeProc": resumeProc,
  2430.                          "dsCallerResumeArgs" : resumeArgs,
  2431.                          "dsCallerSuppressUI" : suppressUI,
  2432.                          "dsCallerCloseUI" : closeUI};
  2433.  
  2434.       // before running resumeProc and resumeArgs, will call
  2435.       // LoadDataScriptFinishProc it load up all scripts DataScript requires
  2436.       this.LoadAndCacheScriptAsync(loadScriptArgs,
  2437.                                    this.LoadDataScriptFinishProc, dsFinishArg,
  2438.                                    suppressUI, closeUI);
  2439.     },
  2440.  
  2441.  
  2442.     //
  2443.     // Manual Update Procs
  2444.     //
  2445.     // this is called when DataScript.entryPoint() is done
  2446.     ManualUpdateCallBackProc: function(args)
  2447.     {
  2448.       try {
  2449.         updater.console.println("ManualUpdateCallBackProc()"); 
  2450.         updater.MasterScript.saveState();  // can raise 
  2451.       }
  2452.       catch (e) {
  2453.         updater.console.println("Exception in ManualUpdateCallBackProc: " + e);
  2454.       }
  2455.     },
  2456.  
  2457.     // this is called when DataScript and its depending scripts has been downloaded
  2458.     ManualUpdateFinishProc: function(args)
  2459.     {
  2460.       // call datascript main entry point
  2461.       try {
  2462.         updater.console.println("ManualUpdateFinishProc()"); 
  2463.  
  2464.         args.callBack = updater.MasterScript.ManualUpdateCallBackProc;
  2465.         args.callBackArgs = null;
  2466.         updater.DataScript.entryPoint(args);
  2467.       }
  2468.       catch (e) {
  2469.         updater.console.println("Exception in ManualUpdateFinishProc: " + e);
  2470.       }
  2471.     },
  2472.  
  2473.     ManualUpdateAsync: function()
  2474.     {
  2475.       try {
  2476.         updater.console.println("ManualUpdateAsync()"); 
  2477.         if ( ! this.init(false) ) return;
  2478.  
  2479.         this.loadState();
  2480.  
  2481.         updater.isAutoUpdate = false;
  2482.         updater.useSyncRead = false;
  2483.         var finishProcArgs = {func:"doUpdate", 
  2484.                               args:{isAutoUpdate:false}};
  2485.         this.LoadDataScriptAsync(this.ManualUpdateFinishProc, finishProcArgs);
  2486.         }
  2487.       catch (e) {
  2488.           updater.console.println("Exception in ManualUpdateAsync: " + e);
  2489.           return false;
  2490.       }
  2491.     },
  2492.  
  2493.  
  2494.     //
  2495.     // AutoUpdate and Check DLM Procs
  2496.     // 
  2497.  
  2498.     // this is called when DataScript.entryPoint() and AutoUpdate's
  2499.     // implemention is call and done
  2500.     AutoUpdateCallBackProc: function(args)
  2501.     {
  2502.       try {
  2503.         updater.console.println("AutoUpdateCallBackProc()"); 
  2504.         var isMSUpdated = (updater.MasterScript.PropertyIsDefined(args, "exception") &&
  2505.                           args["exception"] == "MSUpdatedAbort");
  2506.         
  2507.         if ( ! isMSUpdated ) {
  2508.           updater.MasterScript.advanceNextCheckDate();
  2509.           updater.MasterScript.popNotifications();
  2510.           }
  2511.         else {
  2512.           updater.console.println("MasterScript is updated. skipping advanceNextCheckDate() and popNotifications()");
  2513.           }
  2514.         updater.MasterScript.saveState();  // can raise 
  2515.       }
  2516.       catch (e) {
  2517.         updater.console.println("Exception in AutoUpdateCallBackProc: " + e);
  2518.       }
  2519.     },
  2520.  
  2521.     // this is called when DataScript has been downloaded
  2522.     AutoUpdateFinishProc: function(args)
  2523.     {
  2524.       // call datascript main entry point
  2525.       try {
  2526.         updater.console.println("AutoUpdateFinishProc()"); 
  2527.  
  2528.         args.callBack = updater.MasterScript.AutoUpdateCallBackProc;
  2529.         args.callBackArgs = null;
  2530.         updater.DataScript.entryPoint(args);
  2531.       }
  2532.       catch (e) {
  2533.         updater.console.println("Exception in AutoUpdateFinishProc: " + e);
  2534.       }
  2535.     },
  2536.  
  2537.  
  2538.     CheckDLMStateFinishProc: function(args)
  2539.     {
  2540.       // call datascript main entry point
  2541.       try {
  2542.         updater.console.println("CheckDLMStateFinishProc()");
  2543.         // nothing to do after CheckDLMState implementation is called thus
  2544.         // args.callBack is not needed
  2545.         updater.DataScript.entryPoint(args);
  2546.         }
  2547.       catch (e) {
  2548.         updater.console.println("Exception in CheckDLMStateFinishProc: " + e);
  2549.         }
  2550.     },
  2551.  
  2552.     AutoUpdateAsync: function()
  2553.     {
  2554.       try {
  2555.         updater.console.println("AutoUpdateAsync()"); 
  2556.  
  2557.         if ( ! this.init(true) ) return;
  2558.  
  2559.         // do a quick check before using CodeScript's CheckDLMState() which
  2560.         // has dialogs.
  2561.         var dlmState = updater.dlm.getState();
  2562.         updater.console.println("  updater.dlm.getState() returns " + dlmState);
  2563.         // DLM not running.  rdy to accept transaction
  2564.         // quickly return
  2565.         if (dlmState != 0) { 
  2566.           // DLM has pending stuff
  2567.           // ok.  now we must do some UI since there are pending updates
  2568.           // calls into CodeScript's CheckDLMState()
  2569.           
  2570.           if (! updater.MasterScript.checkNetConnection(true) ) {
  2571.             // if no net, try if all scripts are cached already.
  2572.             var hasAllScripts = updater.MasterScript.getAllScriptsFromStore();
  2573.             if (hasAllScripts) {
  2574.               updater.DataScript.entryPoint({func:"CheckDLMState", args:{}}); 
  2575.               }
  2576.             }
  2577.           else {
  2578.             // has net connection
  2579.             // finishProcArgs is the args for calling DataScript.entryPoint(args)
  2580.             var finishProcArgs = {func:"CheckDLMState", 
  2581.                                   args:{}};
  2582.             this.LoadDataScriptAsync(this.CheckDLMStateFinishProc, finishProcArgs, true);
  2583.             }
  2584.           return;
  2585.           }
  2586.         else {
  2587.           // continue AutoUpdate
  2588.           this.loadState();
  2589.  
  2590.           // check if pref is set the monthly
  2591.           // monthly: 1
  2592.           // manually: 0
  2593.           var freq = updater.app.getUpdateFrequency();
  2594.           updater.console.println("  freq = " + freq);
  2595.  
  2596.           // do auto update when it is time to AND freq is monthly
  2597.           if ( (freq == 1) &&  this.isTimeToUpdate() ) {
  2598.             // silently returns if autoupdate and no net
  2599.             if (! updater.MasterScript.checkNetConnection(true) ) {
  2600.               return false;
  2601.               }
  2602.             
  2603.             updater.isAutoUpdate = true;
  2604.             updater.useSyncRead = true;
  2605.  
  2606.             // finishProcArgs is the args for calling DataScript.entryPoint(args)            
  2607.             var finishProcArgs = {func:"doUpdate", 
  2608.                                   args:{isAutoUpdate:true}};
  2609.             this.LoadDataScriptAsync(this.AutoUpdateFinishProc, finishProcArgs, true);
  2610.             }
  2611.           else {
  2612.             // pop new notifications. calls only finish auto-update check, not
  2613.             // manual check
  2614.             this.popNotifications();
  2615.             this.saveState();  // can raise
  2616.             }
  2617.           }
  2618.         }
  2619.       catch (e) {
  2620.         updater.console.println("Exception in AutoUpdateAsync: " + e);
  2621.         return false;
  2622.         }
  2623.     },
  2624.  
  2625.  
  2626.     //
  2627.     // FindComponent Procs
  2628.     // 
  2629.     // this is called when DataScript.entryPoint() is done
  2630.     FindComponentCallBackProc: function(args)
  2631.     {
  2632.       try {
  2633.         updater.console.println("FindComponentCallBackProc()"); 
  2634.  
  2635.         var ret = args["returnVal"];
  2636.         updater.console.println("ComponentFound = " + ret); 
  2637.         updater.MasterScript.saveState();  // can raise 
  2638.       }
  2639.       catch (e) {
  2640.         updater.console.println("Exception in FindComponentCallBackProc: " + e);
  2641.       }
  2642.     },
  2643.  
  2644.     // this is called when DataScript has been downloaded
  2645.     FindComponentFinishProc: function(args)
  2646.     {
  2647.       // call datascript main entry point
  2648.       try {
  2649.         updater.console.println("FindComponentFinishProc()"); 
  2650.  
  2651.         args.callBack = updater.MasterScript.FindComponentCallBackProc;
  2652.         args.callBackArgs = null;
  2653.         updater.DataScript.entryPoint(args);
  2654.       }
  2655.       catch (e) {
  2656.         updater.console.println("Exception in FindComponentFinishProc: " + e);
  2657.       }
  2658.     },
  2659.  
  2660.     FindComponentAsync: function(type, name, desc, ver, params)
  2661.     {
  2662.       try {
  2663.         updater.console.println("FindComponentAsync()"); 
  2664.  
  2665.         if ( ! this.init() ) return;
  2666.  
  2667.         this.loadState();
  2668.  
  2669.         var hasNet = updater.net.isConnected();
  2670.         var wellKnown = false;
  2671.  
  2672.         if ( !desc || desc.length == 0 ) {
  2673.           // no desc given by caller.  try lookup well known component
  2674.           // description
  2675.           var knownDesc = this.lookUpWellKnownCompDesc(type, name);
  2676.           if (knownDesc && knownDesc.length > 0) {
  2677.             wellKnown = true;
  2678.             desc = knownDesc;
  2679.             }
  2680.           else {
  2681.             wellKnown = false;
  2682.             desc = type + "/" + name;
  2683.             if (ver) desc = desc + ":" + ver;
  2684.             }
  2685.           }
  2686.  
  2687.         updater.console.println("  wellKnown = " + wellKnown);
  2688.         updater.console.println("  desc      = " + desc);
  2689.         // if no net, prompt user if connecting to net is ok
  2690.         if (! hasNet) {
  2691.           var cont;
  2692.           if (wellKnown) {
  2693.             cont = this.showMissingCompDialog(desc);
  2694.             }
  2695.           else {
  2696.             cont = this.showMissingCompDialog();
  2697.             }
  2698.           // no = 3,  yes =4
  2699.           if (cont == 3) return false;
  2700.           }
  2701.         
  2702.         // user wants to continue.  forward request to CodeScript via DataScript
  2703.         // download the datascript (may need to connect to net)
  2704.  
  2705.  
  2706.         var finishProcArgs = {func:"findComponent", 
  2707.                               args:{type:type, name:name, desc:desc, ver:ver, params:params}};
  2708.         this.LoadDataScriptAsync(this.FindComponentFinishProc, finishProcArgs);
  2709.         return true;
  2710.         }
  2711.       catch (e) {
  2712.           updater.console.println("Exception in FindComponentAsync: " + e);
  2713.           return false;
  2714.       }
  2715.     },
  2716.  
  2717.  
  2718.  
  2719.     __ENDER__:"END"
  2720. };
  2721.  
  2722. ScriptObj;
  2723. //
  2724. // StartUp.js
  2725. // 
  2726. // Edit History:
  2727. // Danny Siu: Fri Apr 18 01:35:10 2003
  2728. // End History
  2729. //
  2730. // [SHOULD REMOVE ALL THE COMMENTS FROM PRODUCTION!!!]
  2731. // 
  2732. // the sole purpose of bootstrap script is to load up the masterscript and
  2733. // make sure it exists in Updater JS runtime (ie: defines
  2734. // updater.MasterScript).  it must also define a updater.scriptRootURL which
  2735. // can be used to defer the location of MasterScript on the server.
  2736. //
  2737. // during developement, the MasterScript is always loaded from a server by
  2738. // doing urlGet().  For release, there should be a presisted MasterScript in
  2739. // user's dir and the bootstrap script should load up the presist file and
  2740. // bring the cached MasterScript back to life.
  2741. //
  2742. // 2002-12-11 Updates: 
  2743. // 
  2744. // Here is how MasterScript would be loaded up: 
  2745. // 
  2746. // 1) First check if an presisted version in updater.store is available.  If
  2747. // so, check its version againt updater.MasterScript( if it is even defined
  2748. // in the runtime probably because of bootstrap.js evaluation)
  2749. //
  2750. // Then set updater.MasterScript to the newer version.  This allow us to
  2751. // update and override MasterScript later on.
  2752. //
  2753. // 2) if NOT, use darn simple urlGet() to fetch it from
  2754. // updater.masterScriptURL the newly fetched script will be presisted so that
  2755. // it doesn't need to be refetch next time
  2756. // 
  2757. //
  2758. // updater.bootStrapped is a globle which C++ code can check if bootstrapping
  2759. // has happened.  it is for optimization so that bootstrip.js will only be
  2760. // opened and eval'ed once per app launch.
  2761. //
  2762. // updater.scriptRootURL is the base of where all scripts will live on server
  2763. //
  2764.  
  2765. // The stable set of scripts updated once or twice a week for QE and Dev
  2766. // This is the default location for Updater scripts within Adobe
  2767. // updater.scriptRootURL = "http://mcmug.corp.adobe.com/~dsiu/NewportUpdater/js/";
  2768.  
  2769. // Lastest and greatest scripts for development and limited QE testing
  2770. // Uncomment the following line if you want to try the latest scripts
  2771. // updater.scriptRootURL = "http://mcmug.corp.adobe.com/~dsiu/NewportUpdater/js_dev/";
  2772.  
  2773. // For my own development using local web server
  2774. // do not uncomment the following unless you know what you are doing 
  2775. // updater.scriptRootURL = "http://127.0.0.1/NewportUpdater/js/";
  2776.  
  2777. // For Beta3 deployment
  2778. updater.scriptRootURL = "http://update.adobe.com/pub/adobe/acrobat/js/6.x/";
  2779.  
  2780. // updater.bootStrapped = false;
  2781.  
  2782.  
  2783. if (! updater.bootStrapped) {
  2784.  
  2785.   try {
  2786.     updater.console.println("===== Loading bootstrap.js =====");
  2787.  
  2788.     // Since MasterScript WILL be prepended this file to form bootstrap.js, need
  2789.     // to check if ScriptObj exists and and pick it up as MasterScript
  2790.     if (typeof(ScriptObj) != "undefined") {
  2791.       updater.console.println("  picked up default MasterScript from bootstrap.js");
  2792.       updater.MasterScript = ScriptObj;
  2793.     }
  2794.  
  2795.     // overrideable scriptRootURL by Pref
  2796.     // updater.avpref can raise if the pref section/key not defined
  2797.     try {
  2798.       updater.scriptRootURL = updater.avpref.get("Updater", 
  2799.                                                  "ScriptRootURL", 
  2800.                                                  updater.avpref.type["String"], 
  2801.                                                  updater.scriptRootURL);
  2802.       updater.console.println("  overriding scriptRootURL from pref");
  2803.     } catch (e) {}  // safely ignore the raise by avpref 
  2804.  
  2805.     updater.console.println("  updater.scriptRootURL = " + updater.scriptRootURL);
  2806.  
  2807.     // first check if there is a presisted version (the following code has
  2808.     // CANNOT assume existence of MasterScripts and its friends of utilities
  2809.     // functions)
  2810.  
  2811.     try {
  2812.       updater.store.load();
  2813.       }
  2814.     catch (e) {
  2815.       updater.console.println("Exception in trying to do updater.store.load(): " + e);
  2816.       updater.console.println("  --> skip loading store");
  2817.       }
  2818.  
  2819.     var cachedMSVersion;
  2820.     var cachedMSName = "cachedMasterScript";
  2821.     cachedMSName = cachedMSName + "_" + updater.app.viewerType + "_" + updater.app.language;
  2822.     var curRunTimeMSVersion;
  2823.  
  2824.     var gotMasterScript = false;
  2825.  
  2826.     
  2827.     // version checking 
  2828.  
  2829.     // finding out cached MasterScript version
  2830.     if ( typeof(updater.store.perUser[cachedMSName]) != "undefined" &&
  2831.          typeof(updater.store.perUser[cachedMSName]["scriptObj"]) != "undefined" )
  2832.       {
  2833.       cachedMSVersion = updater.store.perUser[cachedMSName].scriptObj.version + 0.0;
  2834.       updater.console.println(" checking cachedMSVersion = " + cachedMSVersion);
  2835.       }
  2836.     else {
  2837.       cachedMSVersion = 0.0;
  2838.       }
  2839.  
  2840.     // finding out current MasterScript version
  2841.     if ( (typeof(updater["MasterScript"]) != "undefined" ) &&
  2842.          (typeof(updater.MasterScript["version"]) != "undefined") ) 
  2843.       {
  2844.       curRunTimeMSVersion = updater.MasterScript.version + 0.0;
  2845.       updater.console.println(" checking curRunTimeMSVersion = " + curRunTimeMSVersion);
  2846.       }
  2847.     else {
  2848.       curRunTimeMSVersion = 0.0;
  2849.       }
  2850.  
  2851.     if ( (curRunTimeMSVersion != 0) && (curRunTimeMSVersion > cachedMSVersion) ) {
  2852.       updater.console.println("--> Using MasterScript from current runtime.  version = " + curRunTimeMSVersion);
  2853.       gotMasterScript = true;
  2854.       }
  2855.  
  2856.     // MUST use >= to compare cached verion with the current one in runtime
  2857.     // since current one in runtime may well be the cached one when bootstrip
  2858.     // is eval the second time
  2859.     if ( !gotMasterScript &&
  2860.          (cachedMSVersion != 0) && (cachedMSVersion >= curRunTimeMSVersion) ) {
  2861.       updater.MasterScript = updater.store.perUser[cachedMSName].scriptObj;
  2862.       updater.console.println("--> Using MasterScript from cache.  version = " + cachedMSVersion);
  2863.       gotMasterScript = true;
  2864.       }
  2865.  
  2866.     if (!gotMasterScript) {
  2867.       // no existing MasterScript....do a urlGet();
  2868.       // first check if there is net connection
  2869.       var hasNet; 
  2870.       if ( typeof(updater.net["isConnected"]) != "undefined") {
  2871.         hasNet = updater.net.isConnected();
  2872.         }
  2873.       else {
  2874.         hasNet = updater.dlm.hasNetAccess();
  2875.         }
  2876.       
  2877.       if (! hasNet) {
  2878.         // should use UIScript's showErrorDialog() when UIScript is presisted.
  2879.         // for now just do app.alert.
  2880.         var title = updater.app.getUpdaterString("bsJSNoNetConnectTitle");
  2881.         var errMsg = updater.app.getUpdaterString("bsJSNoNetConnectText");
  2882.         updater.app.alert({nIcon:0, nType:0, cTitle:title, cMsg:errMsg});
  2883.         }
  2884.       else {
  2885.         updater.console.println("  fetching MasterScript with urlGet()");
  2886.  
  2887.         // should add prod config into creating the URL later
  2888.         var masterScriptURL = updater.scriptRootURL + "MasterScript.js";
  2889.  
  2890.         var resp = updater.net.urlGet(masterScriptURL);
  2891.  
  2892.         updater.console.println("  eval MasterScript");
  2893.         var newScriptObj = eval( resp.Content );
  2894.         updater.console.println("  eval MasterScript doone");
  2895.         if ( newScriptObj == null ) {
  2896.           updater.console.println("  something wrong while eval resp.Content.  throws!");
  2897.           throw "badData";
  2898.           }
  2899.         updater.MasterScript = newScriptObj;
  2900.         
  2901.         updater.console.println("  saving MasterScript");
  2902.         // can null be used for cachedDate?
  2903.         updater.store.perUser[cachedMSName] = { cachedDate : null,
  2904.                                                 scriptObj : newScriptObj };
  2905.  
  2906.         // save user store
  2907.         try {
  2908.           updater.store.save();
  2909.           }
  2910.         catch (e) {
  2911.           updater.console.println("Exception in trying to updater.store.save(): " + e);
  2912.           throw new Error("SaveStateException");
  2913.           }
  2914.         
  2915.         gotMasterScript = true;
  2916.         }
  2917.       }
  2918.  
  2919.     updater.bootStrapped = gotMasterScript;
  2920.  
  2921. //     if (gotMasterScript &&
  2922. //         typeof(updater.MasterScript["InstallPrefPanel"] != "undefined") ) {
  2923. //       updater.console.println("  installing PrefPanel");
  2924. //       updater.MasterScript.InstallPrefPanel();
  2925. //       }
  2926.  
  2927.     updater.console.println("===== bootstrap.js done =====");
  2928.     }
  2929.   catch (e) {
  2930.     updater.console.println("  Exception during bootstrap - " + e);
  2931.     }
  2932. }
  2933. else {
  2934.   updater.console.println("===== bootstrap.js already loaded =====");
  2935. }
  2936.  
  2937.  
  2938.